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. 注意事项
我要赚赏金
