【嵌入式】微芯旺KungFu32A156MQT读取DS18B20温度计
相关资料
(74条消息) DS18B20使用说明_ds18b20复位_Joyin_Lee的博客-CSDN博客
解决DS18B20读取异常的问题 - 知乎 (zhihu.com)
出现问题
为了方便,我从51单片机的例程里面移植,使用串口检查读取数据,但是DS18B20读取数据全部都是1
问题1:使用check函数发现DS18B20不存在
在51单片机上连接串口发现读数也全都是1,原因是串口中断占用的时间扰乱了DS18B20的时序
解决办法:关闭串口,使用DEBUG模式来编程,或者是读取完毕后再开启串口
问题2:解决问题1后发现读出的数据全都是1
使用逻辑分析仪观察51单片机和KF32的时序图,发现51单片机时序清晰,KF32写入DS18B20数据的函数中时序图时和51单片机不一致,
检查各代码运行的时间,发现是在进行GPIO的输入输出转换的时间超过了15us,导致更不上DS18B20的时序,原因是我在变换GPIO模式的时候重启了GPIO。
可见如果超过了DS18B20下拉的时间,那么本来该是低电平0的数据将会读到高电平1。
解决办法:将GPIO设置为输出模式,速度为高速,设置为开漏输出,上拉GPIO口。此时虽然是输出模式但依然可以直接读取到输入的电平,就不用进行输入输出转换了。终于DS18B20可以正常读数
问题3:check函数等待时间修改后,读数又为全是1
原因是单总线对于时序比较严格,等待时间修改后,程序将更快开始下一个指令输出,但是DS18B20的相应未结束,所以导致时序混乱,主从不同步。
代码
GPIO
//GPIOx设置为输出 //输入: GPIOx : 指向GPIO内存结构的指针,取值为GPIOA_SFR~GPIOH_SFR。 // GpioPin : 端口引脚掩码,取值为GPIO_PIN_MASK_0~GPIO_PIN_MASK_15中的一个或多个组合。 void Lp_Gpio_Output_Config(GPIO_SFRmap* GPIOx,uint16_t GpioPin) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_Struct_Init(&GPIO_InitStructure); GPIO_InitStructure.m_Pin = GpioPin; GPIO_InitStructure.m_Speed = GPIO_HIGH_SPEED; //初始化 GPIO输出速度 GPIO_InitStructure.m_Mode = GPIO_MODE_OUT; //初始化 GPIO方向为输出 GPIO_InitStructure.m_PullUp = GPIO_PULLUP; //初始化 GPIO上拉 GPIO_InitStructure.m_PullDown = GPIO_NOPULL; //初始化 GPIO不下拉 GPIO_InitStructure.m_OpenDrain =GPIO_POD_OD; //初始化 GPIO为开漏 GPIO_Configuration(GPIOx,&GPIO_InitStructure); }
DS18B20
/* * DS18B20.h * * Created on: 2023-2-24 * Author: l22200182 */ #ifndef DS18B20_H_ #define DS18B20_H_ #include "Lp_Gpio.h" //设置GPIO #define DQ_GPIO_SFR GPIOH_SFR #define DQ_PIN_MASK GPIO_PIN_MASK_8 uint8_t DS18B20_Init(void); //初始化DS18B20的IO口DQ,同时检测DS18B20的存在 uint8_t DS18B20_Check(void); //检查DS18B20是否存在 float DS18B20_Read_Temperture(void); //从DS18B20得到温度值 #endif /* DS18B20_H_ */
/* * DS18B20.c * * Created on: 2023-2-24 * Author: l22200182 */ #include "DS18B20.h" //初始化DS18B20的GPIO void DS18B20_Gpio_Init(){ Lp_Gpio_Output_Config(GPIOH_SFR,GPIO_PIN_MASK_8); } //设置DQ电平 void DS18B20_Set_DQ(BitAction BitsValue){ GPIO_Set_Output_Data_Bits(GPIOH_SFR,GPIO_PIN_MASK_8,BitsValue); } //读取DQ电平 BitAction DS18B20_Read_DQ(void){ return GPIO_Read_Input_Data_Bit(GPIOH_SFR,GPIO_PIN_MASK_8);//不修改输出模式直接进行读取 } //复位DS18B20 void DS18B20_Reset(void) { DS18B20_Gpio_Init(); //重新初始化IO DS18B20_Set_DQ(RESET); //拉低DQ systick_delay_us(750); //拉低750us DS18B20_Set_DQ(SET); //拉高DQ systick_delay_us(20); //拉高20us } //检查DS18B20是否存在 //输出: 1:未检测到 // 0:存在 uint8_t DS18B20_Check(void) { uint8_t time_temp=0; while(DS18B20_Read_DQ()&&time_temp<200)//等待DQ为低电平等200us { time_temp++; systick_delay_us(1); } if(time_temp>=200)return 1; else time_temp=0; while((!DS18B20_Read_DQ())&&time_temp<200)//等待DQ为高电平等200us { time_temp++; systick_delay_us(1); } if(time_temp>=200)return 1;//如果超时强制返回1 return 0; } //从DS18B20读取一个位 //输出: 0/1 uint8_t DS18B20_Read_Bit(void){ uint8_t de; uint8_t dat=0; DS18B20_Gpio_Init(); DS18B20_Set_DQ(RESET); systick_delay_us(1); DS18B20_Set_DQ(SET); systick_delay_us(1);//这段时间不能过长,必须15us内读取数据 if(DS18B20_Read_DQ())dat=1;//如果总线上高电平则数据为1 else dat=0;//低电平则数据为0 systick_delay_us(50); return dat; } //从DS18B20读取一个字节 //输出: 一个字节的数据 uint8_t DS18B20_Read_Byte(void) { uint8_t i=0; uint8_t dat=0; uint8_t temp=0; //循环8次,每次读取1位,且先读低位后读高位 for(i=0;i<8;i++){ temp=DS18B20_Read_Bit(); dat=(temp<<7)|(dat>>1); } return dat; } //写一个字节给DS18B20 //输入: dat:要写入的字节 void DS18B20_Write_Byte(uint8_t dat){ uint8_t de; uint8_t i=0; uint8_t temp=0; DS18B20_Gpio_Init(); //循环8次,每次写1位,且先写低位后写高位 for(i=0;i<8;i++){ temp=dat&0x01;//选择低位准备写入 dat>>=1;//将次高位移入低位 if(temp){ DS18B20_Set_DQ(RESET); systick_delay_us(1); DS18B20_Set_DQ(SET); systick_delay_us(60); }else{ DS18B20_Set_DQ(RESET); systick_delay_us(60); DS18B20_Set_DQ(SET); systick_delay_us(1); } } } //开始温度转换 void DS18B20_Start(void){ DS18B20_Reset(); //复位 DS18B20_Check(); //检查DS18B20 DS18B20_Write_Byte(0xcc); //SKIP ROM 1100 1100 DS18B20_Write_Byte(0x44); //转换命令 0100 0100 } //初始化DS18B20的IO口DQ,同时检测DS18B20的存在 //输出: 1:不存在 // 0:存在 uint8_t DS18B20_Init(void){ DS18B20_Gpio_Init(); DS18B20_Reset(); return DS18B20_Check(); } //从DS18B20得到温度值 //输出: 温度数据 float DS18B20_Read_Temperture(void){ float temp; uint8_t dath=0; uint8_t datl=0; uint16_t value=0; DS18B20_Start(); //开始转换 systick_delay_ms(250); //转换时间 systick_delay_ms(250); DS18B20_Reset(); //复位 DS18B20_Check(); DS18B20_Write_Byte(0xcc);//SKIP ROM DS18B20_Write_Byte(0xbe);//读存储器 datl=DS18B20_Read_Byte();//低字节 dath=DS18B20_Read_Byte();//高字节 value=(dath<<8)+datl; //合并为16位数据 if((value&0xf800)==0xf800){//判断符号位,如果为负温度 value=(~value)+1; //负数的补码需要取反加1 temp=value*(-0.0625); //转换为摄氏度 }else{ temp=value*0.0625; //正数 } return temp; }
main
#include "main.h" int main(){ SystemInit(120); systick_delay_init(120); DS18B20_Init(); //初始化 float temp_value=DS18B20_Read_Temperture(); //读取温度 while(1){ } }