课程3的任务目标是实现温度报警器,采集DS18B20的温度数据并实时显示。我们通过课程三的学习掌握了ADC采集的相关配置以及应用,不过课后的习题所使用的DS18B20是数字型温度传感器,在实际的任务实现过程中并没有用到ADC的相关知识。
这一次我们使用的的器件有数码管模块、有源扬声器模块、DS18B20温度传感器模块。我们先了解一下新模块。
有源扬声器模块:
本模块通过一个三极管进行驱动,并且是低电平触发,实际这块的控制只要通过一个引脚技能实现;
DS18B20温度传感器模块:
这个是这次任务比较难得一部分,DS18B20是通过单总线的方式进行通信的,这种通信协议对于时序的要求是非常严格的,我们需要根据时序图去编写起始、数据传输、结束等通信阶段。
我们在找到了一个DS18B20的驱动文件以及数据手册进行驱动的快速设计,单总线也就是所有通信都是通过这一根线实现的,我们需要根据时序切换输入输出状态,为了方便创建如下程序:
void delay_us(uint32_t Data) { delay_cycles(Data*32); } void ConfigDQ_IN(void)//配置为输入 { DL_GPIO_disableOutput(GPIO_18B20_PORT, GPIO_18B20_PIN_Tem_PIN); DL_GPIO_initDigitalInput(GPIO_18B20_PIN_Tem_IOMUX); DL_GPIO_setPins(GPIO_18B20_PORT, GPIO_18B20_PIN_Tem_PIN); DL_GPIO_enableOutput(GPIO_18B20_PORT, GPIO_18B20_PIN_Tem_PIN); } void ConfigDQ_OUT(void)//配置为输出入 { DL_GPIO_disableOutput(GPIO_18B20_PORT, GPIO_18B20_PIN_Tem_PIN); DL_GPIO_initDigitalOutput(GPIO_18B20_PIN_Tem_IOMUX); DL_GPIO_setPins(GPIO_18B20_PORT, GPIO_18B20_PIN_Tem_PIN); DL_GPIO_enableOutput(GPIO_18B20_PORT, GPIO_18B20_PIN_Tem_PIN); }
配置初始状态:
uint8_t DS18B20_Rst(void) { uint8_t Time=0; ConfigDQ_OUT(); //设置为输出 DQReset; //拉低DQ delay_us(750); //拉480us DQSet; //DQ=1 delay_us(60); //60US ConfigDQ_IN(); //设置为输入 //等待ds18b20回应 while (ReadDQ==1 && Time<200) { Time++; delay_us(1); } if(Time>200) return 1; else Time=0; while (ReadDQ == 0 && Time<240) { Time++; delay_us(1); } if(Time>240) return 1; else return 0; }
写数据:
void Write_Byte(uint8_t data) { uint8_t i; uint8_t bit; ConfigDQ_OUT(); //设置为输出 for (i=1;i<=8;i++) { bit=data&0x01; data=data>>1; if(bit) // 写1 { DQReset; delay_us(2); DQSet; delay_us(60); } else //写0 { DQReset; delay_us(60); DQSet; delay_us(2); } } }
读数据:
uint8_t Read_Byte(void) { uint8_t i,bit,data; data=0; for (i=1;i<=8;i++) { ConfigDQ_OUT(); //设置为输出 DQReset; delay_us(2); ConfigDQ_IN(); //设置为输入 delay_us(10); if(ReadDQ) bit=1; else bit=0; delay_us(48); //将获得的dt放在最前面,然后再右移一下空出最前面的位置 data=(bit<<7)|(data>>1); } return data; }
接下来就是数据的读取了:
uint16_t GetTemp(void) { uint16_t tem; uint8_t temp,TH,TL; DS18B20_Rst(); Write_Byte(0xcc); Write_Byte(0x44); DS18B20_Rst(); Write_Byte(0xcc); Write_Byte(0xbe); TL=Read_Byte(); TH=Read_Byte(); if(TH>7) { TH=~TH; TL=~TL; temp=0;//温度为负 } else temp=1;//温度为正 tem=TH;//获取高八位数据 tem<<=8; tem+=TL;//获取低八位数据 tem=(float)tem*0.625; if(temp) return tem;//温度为正 else return -tem;//温度为负 }
在定时器中调用GetTemp(void)获取温度,为什么要放到定时器里呢,因为中断发生会影响单总线的时序正确性,导致数据错误。暂定和之前课程的频率,每500ms采集一次,同时采集后判断温度是否大于280(温度是扩大十倍的值),大于限制就打开蜂鸣器,小于就关闭蜂鸣器。温度报警器功能同样通过按键去开启和关闭。
效果如下: