*** ERROR L105: PUBLIC REFERS TO IGNORED SEGMENT
单片机 项目不知道哪里错了,上网搜说存储器模式改成大型就好了,但是改成大型之后生成的hex文件放进proteus里面CPU直接拉满,1602液晶屏也不显示,还一直发出刺啦刺啦的声音
如果不加上I2C.c那个文件是全部都没问题的,但是一加上I2C就会报一大堆WARNING,
/*-----------------------------------------------
名称:智能温控系统
------------------------------------------------*/
/*-----------------------------------------------
处理器:STC90C516RD+ ,晶振11.0592M
------------------------------------------------*/
#include<reg52.h> //包含头文件,包含特殊功能寄存器的定义
#include<stdio.h>
#include "ds1302.h"
#include "lcd1602.h"
#include "delay.h"
#include "uart.h" ///////项目3中已完成///////
#include "18b20.h"
#include "i2c.h"
#define KEY_PORT (P3|0x1F) //定义按键端口:P3口的后2位
#define KEY_ADD 0xBF //按键ADD按下:10111111
#define KEY_DEC 0x7F //按键DEC按下:01111111
bit ledFlag; //指示灯定时读取标志 /*-----项目4中新增-------*/
bit readtempFlag; //温度定时读取标志 /*-----项目4中新增-------*/
bit readTimeFlag; //时间定时读取标志
bit sendDataFlag; //向上位机定时发送数据标志------项目3中新增加--------
unsigned char tempFlag; //温度区域标志 /*-----项目4中新增-------*/
unsigned char modeFlag; //定义工作模式:0正常,1设置年,2设置月,3设置日,4设置小时,5设置分钟,6设置温度上限,7设置温度下限
bit cmdFlag; //收到上位机命令标志,项目3中增加
unsigned char idata cmdBuf[16]; //接收上位机指令缓冲区,项目3中增加
unsigned char idata sendBuf[16]; //定义串口发送缓冲区,项目3中增加
sbit LED0 = P1^0; //定义状态指示灯 /*-----项目4中新增-------*/
sbit SPEAKER = P1^2; //定义喇叭端口 /*-----项目4中新增-------*/
sbit RELAY1 = P2^2; //定义继电器信号输出端口1 /*-----项目4中新增-------*/
sbit RELAY2 = P2^3; //定义继电器信号输出端口2 /*-----项目4中新增-------*/
void Init_Timer0(void); //定时器初始化
unsigned char Key_Scan(void); //键盘扫描
void Alarm(unsigned int count); //报警控制函数 /*-----项目4中新增-------*/
//设备开关控制函数(relay1-加热器/relay2-制冷器,flag=1继电器开/=0继电器关)
void Device(unsigned int relay,unsigned int flag); /*-----项目4中新增-------*/
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void Init_Timer0(void)
{
///////项目2中已完成:对定时器T0初始化///////
TMOD |=0x01;
TH0=(65536-2000)/256;
TL0=(65536-2000)/256;
EA=1;
ET0=1;
TR0=1;
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void Timer0_isr(void) interrupt 1
{
unsigned int num = 0;
///////项目2中已完成:每秒钟设置一次变量readTimeFlag为1////////
TH0=(65536-2000)/256; //2ms
TL0=(65536-2000)%256;
num++;
if(num%500==0) //每隔500次 即一秒钟进行读时间标志位置1,用于定时读取ds1302时间
{
readTimeFlag=1;
}
/*--------待完善1:每秒钟设置一次变量readtempFlag为1,读温度-------*/
//注意:此处必须+暂时关闭定时器,防止18b20被干扰时序
if(num%500==0)
{
readtempFlag=1;
TR0=0;
}
/*--------待完善2:-------*/
//以下情况开启状态指示灯ledFlag,且状态指示灯闪烁的频率不同
if((tempFlag==3)&&(num%500==0)) ledFlag=1; //指示灯标志位置1
else if (((tempFlag==2)||(tempFlag==4))&&(num%250==0)) ledFlag=1;//等级2或等级4
else if (((tempFlag==1)||(tempFlag==5))&&(num%100==0)) ledFlag=1;//等级1或等级5
///////项目3中已完成:每10秒设置一次变量sendDataFlag为1///////
if(num==5000)
{
num=0;
sendDataFlag=1;
}
}
/*------------------------------------------------
按键初始化函数
------------------------------------------------*/
void Key_Init(void)
{
///////项目1中已完成////////
EX0=1; //外部中断0打开
IT0=1; //边沿触发
EA=1; //打开总中断
}
/*------------------------------------------------
按键扫描函数,返回扫描键值
------------------------------------------------*/
unsigned char Key_Scan(void)
{
//如果有按键返回键码,如果没有按键返回0xFF
///////项目1中已完成////////
unsigned char keyValue = 0;
if(KEY_PORT!=0xFF)
{
DelayMs(10);
if(KEY_PORT!=0xFF)
{
keyValue = KEY_PORT;
while(KEY_PORT!=0xFF);
return keyValue;
}
}
return 0;
}
/*------------------------------------------------
外部中断INT0函数
------------------------------------------------*/
void KEY_SER (void) interrupt 0 //按键中断服务程序
{
///////项目1中已完成////////
modeFlag++;
if(modeFlag>=8)
{
modeFlag=0;
LCD_Clear();
}
}
/*------------------------------------------------
串口中断程序
------------------------------------------------*/
void UART_SER(void) interrupt 4//串行中断服务程序
{
unsigned char i;//接收长度变量
unsigned char tmp; //存储接收字符
if(RI) //接收中断
{
///////项目3中已完成:接收满足条件的字符到cmdBuf///////
RI = 0;
tmp=SBUF;
if(tmp=='$'){
cmdBuf[0] = tmp;
i=1;
}
else if (tmp!='!'){
cmdBuf[i]= tmp;
i++;
if(i>=16)
i=0; //连续接收最多16个字符信息
}
else
{
cmdBuf[i+1]='0';
i=0;
cmdFlag=1; //接收标志位置1
UART_SendStr("OK");
}
}
}
//报警控制函数
void Alarm(unsigned int count)
{
unsigned char i;
while(count>0)
{
for(i=0;i<200;i++)
{
DelayUs2x(200);
SPEAKER=!SPEAKER;
}
SPEAKER=0;//防止一直给喇叭通电造成损坏
DelayMs(200);
count--;
}
}
//继电器控制外设开关:flag 高电平有效
void Device(unsigned int relay,unsigned int flag)
{
/*--------待完善3:根据relay和flag的状态,控制响应继电器动作-------*/
if ((relay==1)&&(flag==0)) RELAY1 = 0; //relay1关
else if ((relay==1)&&(flag==1)) RELAY1 = 1; //relay1开
else if ((relay==2)&&(flag==0)) RELAY2 = 0; //relay2关
else if ((relay==2)&&(flag==1)) RELAY2 = 1;//relay2开
else return;
}
/*------------------------------------------------
主函数
------------------------------------------------*/
void main (void)
{
unsigned char tempH,tempL; //温度阈值上限、下限
// float temp; //当前温度(项目3使用)
int temp; //当前温度:转换前 /*-----项目4中新增-------*/
float temperature; //当前温度:转换后 /*-----项目4中新增-------*/
float cur_temp; //当前温度:用于显示、串口发送 /*-----项目4中新增-------*/
unsigned char display_data[16]; //定义显示区域缓冲区
unsigned char key; //当前按键键值
unsigned char i;
unsigned char num=0;
LCD_Init(); //初始化液晶
LCD_Clear(); //清屏
Init_Timer0(); //初始化定时器
Key_Init(); //初始化按键中断
Ds1302_Init(); //初始化时钟模块
Lcd_User_Chr(); //写入自定义字符:摄氏度符号
DelayMs(10); //适当延时有助于稳定
//初始化温度阈值
tempL = 10;
tempH = 30;
//设置虚拟温度
// temp = 25.50;
//////项目2中增加的四行代码//////
Ds1302_Read_Time(); //首次读取时间
if((cur_time_buf[2]+cur_time_buf[7])==0) //无效数据,重设初始值
Ds1302_Write_Time();
DelayMs(10);
while (1) //主循环
{
//1-读取系统时间并显示//////项目2中已完成:读取实时时间//////
if(readTimeFlag==1)
{
//读取时间
readTimeFlag=0; //标志位清零
Ds1302_Read_Time(); //读取时间参数
//显示时间
sprintf(display_data,"20%2d-%02d-%02d %02d:%02d",
(int)cur_time_buf[1],(int)cur_time_buf[2],(int)cur_time_buf[3],
(int)cur_time_buf[4],(int)cur_time_buf[5]);//年月日时分
LCD_Write_String(0,0,display_data);//显示第一行
}
/* //2-显示温度和温度阈值(项目3中使用)
sprintf(display_data,"T%2.2f",temp);//格式化温度值
LCD_Write_String(0,1,display_data);//显示在第二行
LCD_Write_Char(6,1,0x01);//写入温度右上角点
LCD_Write_Char(7,1,'C'); //写入字符C
sprintf(display_data,"L%2d H%2d",(int)tempL,(int)tempH);
LCD_Write_String(9,1,display_data);
*/
//2-读取温度并显示
if(readtempFlag==1)
{
readtempFlag=0;
//2-1读取温度并转换,注意:转换完之后重新开启定时器
/*--------待完善4:-------*/
temp=ReadTemperature();
temperature= temp*0.0625; //实际温度转化
TR0=1;
temp>>=4;
if((temperature<0)||(temperature>80)) continue;
//2-2显示温度及温度符号
/*--------待完善5:-------*/
cur_temp = temperature;
sprintf(display_data,"T%2.2f",cur_temp);
LCD_Write_String(0,1,display_data);//显示在第二行
LCD_Write_Char(6,1,0x01);//写入温度右上角点
LCD_Write_Char(7,1,'C'); //写入字符C
//2-3判定温度区域
/*--------待完善6:参考表P4-2,设置tempFlag为1-5-------*/
if(temp<tempL-5)
tempFlag=1;
else if(temp<=tempL)
tempFlag=2;
else if(temp<=tempH)
tempFlag=3;
else if(temp<=tempH+5)
tempFlag=4;
else if(temp>tempH+5)
tempFlag=5;
//2-4五温度区域处理:外设控制
/*--------待完善7:根据tempFlag的不同状态,设置不同的警报提示-------*/
switch(tempFlag)
{
case 1:
LCD_Write_String(9,1," !!"); //报警
Alarm(1);
break;
case 2:
LCD_Write_String(9,1," !");
Device(1,0); //开启加热设备
break;
case 3:
sprintf(display_data,"L%2d H%2d",(int)tempL,(int)tempH);
LCD_Write_String(9,1,display_data);
Device(1,1); //关闭加热设备
Device(2,1); //关闭制冷设备
break;
case 4:
LCD_Write_String(9,1," !");
Device(2,0); //开启制冷设备
break;
case 5:
LCD_Write_String(9,1," !");
Alarm(1); //报警
break;
default:break;
}
}
//状态指示灯控制
/*--------待完善8:如果ledFlag置位,开启状态指示灯-------*/
if(ledFlag)
{
ledFlag=0;
LED0=!LED0;
}
//3-设置模式下检测按键:调整时间、温度阈值设定等
while(modeFlag!=0) //进入调节模式,直到恢复正常模式
{
key=Key_Scan();
if (key!=0xFF) //如果检测到ADD/DEC按键按下
{
switch(modeFlag)
{
case 1: //调年
if((key==KEY_ADD)&&(cur_time_buf[1]<99)) cur_time_buf[1]++;
else if((key==KEY_DEC)&&(cur_time_buf[1]>0)) cur_time_buf[1]--;
LCD_Clear();
sprintf(display_data,"20%2d",(int)cur_time_buf[1]);
LCD_Write_String(0,0,display_data);//显示年
Ds1302_Write_Time();
break;
case 2: //调月
///////项目1中已完成////////
if((key==KEY_ADD)&&(cur_time_buf[2]<12)) cur_time_buf[2]++;
else if((key==KEY_DEC)&&(cur_time_buf[2]>1)) cur_time_buf[2]--;
LCD_Clear();
sprintf(display_data,"%2d",(int)cur_time_buf[2]);
LCD_Write_String(5,0,display_data);//显示年
Ds1302_Write_Time();
break;
case 3: //调日
if((key==KEY_ADD)&&(cur_time_buf[3]<31)) cur_time_buf[3]++;
else if((key==KEY_DEC)&&(cur_time_buf[3]>1)) cur_time_buf[3]--;
LCD_Clear();
sprintf(display_data,"%2d",(int)cur_time_buf[3]);
LCD_Write_String(8,0,display_data);//显示日
Ds1302_Write_Time();
break;
case 4: //调时
if((key==KEY_ADD)&&(cur_time_buf[4]<23)) cur_time_buf[4]++;
else if((key==KEY_DEC)&&(cur_time_buf[4]>0)) cur_time_buf[4]--;
LCD_Clear();
sprintf(display_data,"%2d",(int)cur_time_buf[4]);
LCD_Write_String(11,0,display_data);//显示时
Ds1302_Write_Time();
break;
case 5: //调分
///////项目1中已完成////////
if((key==KEY_ADD)&&(cur_time_buf[5]<59)) cur_time_buf[5]++;
else if((key==KEY_DEC)&&(cur_time_buf[5]>0)) cur_time_buf[5]--;
LCD_Clear();
sprintf(display_data,"%2d",(int)cur_time_buf[5]);
LCD_Write_String(14,0,display_data);//显示时
Ds1302_Write_Time();
break;
case 6: //调温度阈值上限
if((key==KEY_ADD)&&(tempH<50)) tempH++; //调上限+1
else if((key==KEY_DEC)&&(tempH>tempL)) tempH--; //上限-1
LCD_Clear();
sprintf(display_data,"Temp H:%2d (L:%2d)",(int)tempH,(int)tempL);
LCD_Write_String(0,1,display_data); //显示分
break;
case 7: //调温度阈值下限
///////项目1中已完成////////
if((key==KEY_ADD)&&(tempL<tempH)) tempL++; //调下限+1
else if((key==KEY_DEC)&&(tempL>0)) tempL--; //下限-1
LCD_Clear();
sprintf(display_data,"Temp L:%2d (H:%2d)",(int)tempL,(int)tempH);
LCD_Write_String(0,1,display_data); //显示
break;
}//end of switch
}
DelayMs(20);
} //end of mode while
//4-发送串口数据信息给上位机
///////项目3中已完成:满足发送条件时,按照表P3-2的协议格式///////
if(sendDataFlag)
{
sendDataFlag = 0;
sprintf(sendBuf,"20%2d-%02d %02d:%02d",
(int)cur_time_buf[1],(int)cur_time_buf[2],
(int)cur_time_buf[3],(int)cur_time_buf[4],(int)cur_time_buf[5]);//年月日时分
UART_SendStr(sendBuf);
UART_SendStr("\r\n");
sprintf(sendBuf,"T%2.2f%C L%2d H%2d\r",cur_temp,(int)tempL,(int)tempH);//格式化温度
UART_SendStr(sendBuf);
UART_SendStr("\r\n");
}
//5-接收串口命令:更新时钟、温度阈值设定、外设控制
if(cmdFlag)
{
cmdFlag=0;
switch(cmdBuf[1])
{
case 'D':
for(i=0;i<=3;i++)
{
cur_time_buf[i]=(cmdBuf[2*i+3]-0x30)*10+(cmdBuf[2*i+1+3]-0x30);
}//数据整合,如2个数 1和5整合成15
Ds1302_Write_Time();
break;
case 'T':
for(i=0;i<=1;i++)
{
cur_time_buf[i+4]=(cmdBuf[2*i+3]-0x30)*10+(cmdBuf[2*i+1+3]-0x30);/*^^^^^^^^^待完善处8:^^^^^^^^*/
}//数据整合,如2个数 1和5整合成15
Ds1302_Write_Time();
break;
case 'H':
temp=(cmdBuf[3]-0x30)*10+(cmdBuf[4]-0x30);
tempH=temp;
break;
case 'L':
temp=(cmdBuf[3]-0x30)*10+(cmdBuf[4]-0x30);/*^^^^^^^^^待完善处9:^^^^^^^^*/
tempL=temp;
break;
default:
break;
}
}
DelayMs(10);
}//end of while
}


C51的函数,如果在中断和普通函数里都会调用,要标记为可重入。而标记为可重入只是解决软件上的问题,逻辑上的冲突因为无法避免。所以最好不要出现这种情况