0.任务目标
用DS18B20实现环境温度的采样,用数码管显示,并实现高温蜂鸣器报警
1. 硬件原理
用到数码管,蜂鸣器,和DS18B20 数字温度传感器。
蜂鸣器工作原理
蜂鸣器分为有源和无源。这里的“源”不是指电源,而是指震荡源。也就是说,有源蜂鸣器内部带震荡源,所以只要一通电就会叫。而无源内部不带震荡源,所以如果用直流信号无法令其鸣叫。必须用2K~5K的方波去驱动它。有源蜂鸣器往往比无源的贵,就是因为里面多个震荡电路。
DS18B20 工作原理
单总线接口:只需要一条数据线即可完成数据的发送和接收,外加一条接地线和电源线。
温度范围:测量范围通常是-55°C 到 +125°C,具有较高的精度,在-10°C到+85°C范围内误差为±0.5°C。分辨率:可设置为9位到12位,对应的温度分辨率从0.5°C到0.0625°C。自带ROM:每个DS18B20都有一个独一无二的64位序列号,便于在单总线上挂接多个设备。
所有的单总线器件要求采用严格的信号时序,以保证数据的完整性。DS18B20 共有 6 种信
号类型:复位脉冲、应答脉冲、写 0、写 1、读 0 和读 1。所有这些信号,除了应答脉冲以外, 都由主机发出同步信号。并且发送所有的命令和数据都是字节的低位在前。
这里我们简单介绍 这几个信号的时序。
1)复位脉冲和应答脉冲
单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平时间至少 480
us,,以产生复位脉冲。接着主机释放总线,4.7K 的上拉电阻将单总线拉高,延时 15~60 us,并进入接收模式(Rx)。接着 DS18B20 拉低总线 60~240 us,以产生低电平应答脉冲,
若为低电平,再延时 480 us。
2)写时序
写时序包括写 0 时序和写 1 时序。所有写时序至少需要 60us,且在 2 次独立的写时序之间 至少需要 1us 的恢复时间,两种写时序均起始于主机拉低总线。写 1 时序:主机输出低电平, 延时 2us,然后释放总线,延时 60us。写 0 时序:主机输出低电平,延时 60us,然后释放总线,延时 2us。
3)读时序
单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出读数据命令后,
必须马上产生读时序,以便从机能够传输数据。所有读时序至少需要 60us,且在 2 次独立的读时序之间至少需要 1us 的恢复时间。每个读时序都由主机发起,至少拉低总线 1us。主机在读 时序期间必须释放总线,并且在时序起始后的 15us 之内采样总线状态。典型的读时序过程为:
主机输出低电平延时 2us,然后主机转入输入模式延时 12us,然后读取单总线当前的电平,然后延时 50us。
在了解了单总线时序之后,我们来看看 DS18B20 的典型温度读取过程,DS18B20 的典型
温度读取过程为:复位à发 SKIP ROM 命令(0XCC)à发开始转换命令(0X44)à延时à复位à发送 SKIP ROM 命令(0XCC)à发读存储器命令(0XBE)à连续读出两个字节数据(即温度)à结束。
2. 软件关键代码
软件配置:
#define PORT_TempSensor_PORT (GPIOA) #define PORT_TempSensor_PIN_TempSensor_PIN (DL_GPIO_PIN_17) #define PORT_TempSensor_PIN_TempSensor_IOMUX (IOMUX_PINCM18) #define PORT_BEEP_PORT (GPIOA) #define PORT_BEEP_PIN__BEEP_PIN (DL_GPIO_PIN_15) #define PORT_LED_Red_PORT (GPIOA) #define PORT_LED_Red_PIN_LED_Red_PIN (DL_GPIO_PIN_0) #define DS18B20_DQ_IN_Read() DL_GPIO_readPins(PORT_TempSensor_PORT,PORT_TempSensor_PIN_TempSensor_PIN) #define delay_us 32 /** * @brief 单总线配置为输入模式 * * @param[in] None * */ void DS18B20_DQ_IN(){ //配置通信引脚为输入模式 DL_GPIO_disableOutput(PORT_TempSensor_PORT, PORT_TempSensor_PIN_TempSensor_PIN); DL_GPIO_initDigitalInput(PORT_TempSensor_PIN_TempSensor_IOMUX); DL_GPIO_setPins(PORT_TempSensor_PORT, PORT_TempSensor_PIN_TempSensor_PIN); DL_GPIO_enableOutput(PORT_TempSensor_PORT, PORT_TempSensor_PIN_TempSensor_PIN); } /** * @brief 单总线配置为输出模式 * * @param[in] None * */ void DS18B20_DQ_OUT(){ //配置通信引脚为输出模式 DL_GPIO_disableOutput(PORT_TempSensor_PORT, PORT_TempSensor_PIN_TempSensor_PIN); DL_GPIO_initDigitalOutput(PORT_TempSensor_PIN_TempSensor_IOMUX); DL_GPIO_setPins(PORT_TempSensor_PORT, PORT_TempSensor_PIN_TempSensor_PIN); DL_GPIO_enableOutput(PORT_TempSensor_PORT, PORT_TempSensor_PIN_TempSensor_PIN); } void DS18B20_OneWireRisingEdge_Config(GPIO_Regs* PORTx,uint32_t PINx,uint32_t t1,uint32_t t2){ DL_GPIO_clearPins(PORTx, PINx); delay_cycles(delay_us*t1); DL_GPIO_setPins(PORT_TempSensor_PORT, PORT_TempSensor_PIN_TempSensor_PIN); delay_cycles(delay_us*t2); } /** * @brief 向DS18B20写入字节数据 * * @param[in] data字节数据 * */ void DS18B20_WRITE_Byte(uint8_t data){ uint8_t byte=data; DS18B20_DQ_OUT(); for(uint8_t i=1;i<=8;i++){ if(byte&0x01){ DS18B20_OneWireRisingEdge_Config(PORT_TempSensor_PORT, PORT_TempSensor_PIN_TempSensor_PIN,2,60); } else{ DS18B20_OneWireRisingEdge_Config(PORT_TempSensor_PORT, PORT_TempSensor_PIN_TempSensor_PIN,60,2); } byte=byte>>1; } } /** * @brief 从DS18B20读取比特数据 * * @param[in] None * */ uint8_t DS18B20_READ_Bit(){ uint8_t bit; DS18B20_DQ_OUT(); DS18B20_OneWireRisingEdge_Config(PORT_TempSensor_PORT, PORT_TempSensor_PIN_TempSensor_PIN,2,5); DS18B20_DQ_IN(); delay_cycles(delay_us*12); if(DS18B20_DQ_IN_Read()) bit=1; else bit=0; delay_cycles(delay_us*50); return bit; } /** * @brief 从DS18B20读取字节数据 * * @param[in] None * */ uint8_t DS18B20_READ_Byte(){ uint8_t bit=0; uint8_t byte=0; for(uint8_t i=1;i<=8;i++){ bit=DS18B20_READ_Bit(); byte|=bit<<(i-1); } return byte; } /** * @brief 判断DS18B20是否存在 * * @param[in] None * */ uint8_t DS18B20_CHECK(){ uint8_t counters=0; DS18B20_DQ_IN(); while(DS18B20_DQ_IN_Read()&&counters<200){ counters++; delay_cycles(delay_us*1); } if(counters>100) //超时未检测到器件,返回1 return 1; else counters=0; while(!(DS18B20_DQ_IN_Read())&&counters<240){ counters++; delay_cycles(delay_us*1); } if(counters>240) //检测到器件但总线电平持续拉低,返回2 return 2; else // DL_UART_transmitData(UART_0_INST,counters); return 0; //检测到器件且总线电平有效,返回0 } /** * @brief 启用DS18B20 * * @param[in] None * */ void DS18B20_START(void){ DS18B20_RESET(); DS18B20_CHECK(); DS18B20_WRITE_Byte(0xcc); DS18B20_WRITE_Byte(0x44); DS18B20_RESET(); DS18B20_CHECK(); DS18B20_WRITE_Byte(0xcc); DS18B20_WRITE_Byte(0xbe); } /** * @brief 初始化DS18B20 * * @param[in] None * */ uint8_t DS18B20_INIT(void){ DS18B20_RESET(); return DS18B20_CHECK(); } /** * @brief 获取DS18B20温度数据(小数点数据) * * @param[in] None * */ float DS18B20_GetTemp(void){ float temp_value=0.0; uint8_t temp_msb,temp_lsb=0; uint16_t temp=0; DS18B20_START(); //采样温度值 temp_lsb=DS18B20_READ_Byte(); temp_msb=DS18B20_READ_Byte(); temp=(temp_msb<<8)+temp_lsb; if((temp&0xF800)==0xF800){ //高5位为1表示负温度 temp=(~temp)+1; //将补码取反运算+1得到负温值 temp_value=temp*(-0.0625); } else temp_value=temp*0.0625; return temp_value; } void tempwarning(void) { float temp = 0; int temp_level[2] = {10,100}; if(DS18B20_INIT()==0){ temp=DS18B20_GetTemp(); if(temp<temp_level[0]){ DL_GPIO_setPins(PORT_BEEP_PORT,PORT_BEEP_PIN__BEEP_PIN); } else if(temp>=temp_level[0]&&temp<temp_level[1]){ DL_GPIO_togglePins(PORT_BEEP_PORT,PORT_BEEP_PIN__BEEP_PIN); } else { DL_GPIO_clearPins(PORT_BEEP_PORT,PORT_BEEP_PIN__BEEP_PIN); } } else{ temp=0.1000; DL_GPIO_setPins(PORT_BEEP_PORT,PORT_BEEP_PIN__BEEP_PIN); delay_cycles(delay_us*1000);//温度传感器不存在、异常,LED_Red不断闪烁 DL_GPIO_togglePins(PORT_LED_Red_PORT,PORT_LED_Red_PIN_LED_Red_PIN); } }
3. 实现效果
4. 注意事项