基于8G单片机的手机蓝牙温控程序 手机(安卓版)通过蓝牙与单片机通信,1秒钟读取1次温度数据与运行参数,也可以
实物图如上,温度传感器置于冰箱冷冻室内,蓝牙串口模块型号是大厦龙雀的BT-04E ,模块资料可在大厦龙雀官网上下载。单片机主时钟22.1184M,串口波特率9600,8位数据位,1个停止位,无校验。 手机APP界面如下图:
用C#做了个串口操作工具,可以用电脑串口来直接读写数据,运行界面如下:
部分程序源码如下:
- voidmain() //程序开始运行的入口
- {
- u8 i;
- u16 crc;
- u8 LED_Data = 0XFE;
- u8 num=0;
- u8 LED_DataTab[8] = { 0XFE,0XFD,0XFB,0XF7,0XEF,0XDF,0XBF,0X7F};
- int TempVal,TempValb; //TempVal大于0的温度, TempValb小于0的温度
- sys_init(); //IO口初始化
- P1M0 = 0x00; //设置P1.0为ADC口
- P1M1 = 0x01;
- ydsx=-250;
- ydxx=150;
- ydjz=0;
- P_SW2|=0x80;
- ADCTIM=0x3f;//设置ADC内部程序
- P_SW2&=0x7f;
- ADCCFG=0x2f;//设置ADC时钟为系统时钟/2/16
- ADC_CONTR=0x80;//使能ADC选P10为ADC通道
- //EEPROM读操作,读取第0扇区,10 12 14字节-------------------
- ydsx=IapRead(SECTOR0 + 10); //从EEPROM第0扇区10字节取温度上限值
- ydxx=IapRead(SECTOR0 + 12); //从EEPROM第0扇区12字节取温度下限值
- ydjz=IapRead(SECTOR0 + 14); //从EEPROM第0扇区14字节取温度校准值
- modbus_reg[0]= ydsx;
- modbus_reg[1]= ydxx;
- modbus_reg[2]= ydjz;
- Timer0_Config(0, MAIN_Fosc / 20000); //t=0:reload值是主时钟周期数, (中断频率, 20000次/秒)
- UART1_config(9600UL,1, 0); // brt: 通信波特率, timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特
- BEEP = 0; //上电蜂鸣响一声
- delay_ms(10); //延时10ms
- BEEP = 1; //关闭蜂鸣响
- tm1650_start();
- write_byte(0x48); //数码显示模式
- tm1650_ack();
- write_byte(0x31); //3级亮度,开显示。这里的指令数据 详情参阅TM1650的datasheet
- tm1650_ack();
- tm1650_end();
- tm1650_start();
- write_byte(0x68);
- tm1650_ack();
- write_byte(Num_Buff[1]);//数码管千位上电显示1
- tm1650_ack();
- tm1650_end();
- tm1650_start();
- write_byte(0x6a);
- tm1650_ack();
- write_byte(Num_Buff[8]);//数码管百位上电显示8
- tm1650_ack();
- tm1650_end();
- tm1650_start();
- write_byte(0x6c);
- tm1650_ack();
- write_byte(Num_Buff[8]); //数码管十位上电显示8
- tm1650_ack();
- tm1650_end();
- tm1650_start();
- write_byte(0x6e);
- tm1650_ack();
- write_byte(Num_Buff[8]); //数码管个位上电显示8
- tm1650_ack();
- tm1650_end();
- Timer0_Config(0, MAIN_Fosc / 20000); //t=0:reload值是主时钟周期数, (中断频率, 20000次/秒)
- UART1_config(9600UL, 1, 0); //brt: 通信波特率, timer=2: 波特率使用定时器2, 其它值:使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1, =1: 切换到P3.6 P3.7, =2:切换到P1.6 P1.7, =3: 切换到P4.3 P4.4.
- EA = 1;
- while(1) //无限循环
- {
- if(B_RX1_OK && !B_TX1_Busy) //收到数据, 进行MODBUS-RTU协议解析
- {
- if(MODBUS_CRC16(RX1_Buffer, RX1_cnt) == 0) //首先判断CRC16是否正确, 不正确则忽略, 不处理也不返回信息
- {
- if((RX1_Buffer[0] ==0x00) || (RX1_Buffer[0] == SL_ADDR)) //然后判断站号地址是否正确, 或者是否广播地址(不返回信息)
- {
- if(RX1_cnt> 2) RX1_cnt -= 2; //去掉CRC16校验字节
- i =MODBUS_RTU(); //MODBUS-RTU协议解析
- if(i != 0) //错误处理
- {
- TX1_Buffer[0]= SL_ADDR; //站号地址
- TX1_Buffer[1]= i; //错误代码
- crc =MODBUS_CRC16(TX1_Buffer, 2);
- TX1_Buffer[2]= (u8)crc; //CRC是小端模式, 先发低字节,后发高字节。
- TX1_Buffer[3]= (u8)(crc>>8);
- B_TX1_Busy= 1; //标志发送忙
- TX1_cnt = 0; //发送字节计数
- TX1_number= 4; //要发送的字节数
- TI =1; //启动发送
- }
- }
- }
- ydsx= modbus_reg[0];
- ydxx=modbus_reg[1];
- ydjz=modbus_reg[2];
- RX1_cnt = 0;
- B_RX1_OK = 0;
- }
- Test(); //按键查询处理
- // delay_ms(500); //延时300ms
- if(TIM_Flag)//TIME0中断10000次(1秒)读一次温度
- {
- ADC_CONTR|=0x40; //启动AD
- _nop_();
- _nop_();
- while(!(ADC_CONTR&0x20)) ; //查询ADC完成标志
- ADC_CONTR &= ~0x20; //清完成标志
- //ADCCFG = 0x00; //设置结果左对齐(会出问题原因不详)
- ADCCFG = 0x20; //设置结果右对齐
- Temp=(ADC_RES << 8) |ADC_RESL; //读取ADC结果
- TempVal = Temp_Cal(Temp)+ydjz; //ADC结果计算成温度值并加上校准值
- //TempVal = Temp_Cal(Temp); //ADC结果计算成温度值
- modbus_reg[3]= TempVal; //温度值写入xdata1003
- //TempVal = Temp; //ADC结果计算成温度值
- if(Run_Flag==0) //如果是制冷模式
- {
- if(TempVal<= ydxx)//实际温度低于温度下限
- {
- Relay=1; //关闭继电器(关闭制冷)
- }
- if(TempVal>= ydsx) //实际温度高于温度上限
- {
- Relay=0; //打开继电器(启动制冷)
- }
- }
- else //否则是制热模式
- {
- if(TempVal<= ydxx) //实际温度低于温度下限
- {
- Relay=0; //打开继电器(启动加热)
- }
- if(TempVal>= ydsx) //实际温度高于温度上限
- {
- Relay=1; //关闭继电器(关闭加热)
- }
- }
- modbus_reg[4]= Relay; ////////继电器状态写入xdata1004
- if(TempVal>= 0) //温度在0度以上
- {
- SEG0 = TempVal/1000%10; //温度千位
- if (SEG0==0)
- SEG0=23; //千位为0时,消隐不显
- SEG1 = TempVal/100%10; //温度百位
- SEG2 = TempVal/10%10; //温度十位
- SEG3 = TempVal/1%10; //温度个位
- DspTemp(); //显示温度
- }
- else //温度在0度以下
- {
- TempValb=abs(TempVal); //取温度绝对值
- SEG0 = 22; //千位显示“-”
- SEG1 = TempValb/100%10; //温度百位
- SEG2 = TempValb/10%10; //温度十位
- SEG3 = TempValb/1%10; //温度个位
- DspTemp();
- }
- TIM_Flag=0;
- }
- }
- }
- //==========================================================
- // 函数: void UART1_ISR (void) interrupt UART1_VECTOR
- // 描述: 串口1中断函数
- // 参数: none.
- // 返回: none.
- // 版本: VER1.0
- // 日期: 2018-4-2
- // 备注:
- //==========================================================
- voidUART1_ISR (void) interrupt UART1_VECTOR
- {
- if(RI)
- {
- RI = 0;
- if(!B_RX1_OK) //接收缓冲空闲
- {
- if(RX1_cnt >=RX1_Length) RX1_cnt = 0;
- RX1_Buffer[RX1_cnt++] =SBUF;
- RX1_TimeOut = 36; //接收超时计时器, 35个位时间
- }
- }
- if(TI)
- {
- TI = 0;
- if(TX1_number != 0) //有数据要发
- {
- SBUF =TX1_Buffer[TX1_cnt++];
- TX1_number--;
- }
- else B_TX1_Busy = 0;
- }
- }
- voidDspTemp()
- {
- write_byte(0x48); //数码显示模式
- tm1650_ack();
- write_byte(0x11); //1级亮度,开显示。这里的指令数据 详情参阅TM1650的datasheet
- tm1650_ack();
- tm1650_end();
- tm1650_start();
- write_byte(0x68);
- tm1650_ack();
- write_byte(Num_Buff[ SEG0]);//显示千位
- tm1650_ack();
- tm1650_end();
- tm1650_start();
- write_byte(0x6a);
- tm1650_ack();
- write_byte(Num_Buff[ SEG1]);//显示百位
- tm1650_ack();
- tm1650_end();
- tm1650_start();
- write_byte(0x6c);
- tm1650_ack();
- write_byte(Num_Buff[ SEG2]+0x80);//显示十位加小数点
- tm1650_ack();
- tm1650_end();
- tm1650_start();
- write_byte(0x6e);
- tm1650_ack();
- write_byte(Num_Buff[ SEG3]); //显示个位
- tm1650_ack();
- tm1650_end();
- }
复制代码
|