有一点C语言基础和华大单片机开发经验,应该就能看得懂就不多介绍了,有疑问可以留言,看到就回了;
关于协议具体解析:传送门@不脱发的程序猿
#include "ds18b20.h" uint8_t DS18B20_Init(void) { stc_gpio_config_t pstcGpioCfg; DDL_ZERO_STRUCT(pstcGpioCfg); Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); pstcGpioCfg.enDir = GpioDirOut; pstcGpioCfg.enDrv = GpioDrvH; //< 端口驱动能力配置->高驱动能力 pstcGpioCfg.enPuPd = GpioNoPuPd; //无上下拉 pstcGpioCfg.enOD = GpioOdDisable; //< 端口开漏输出配置->开漏输出关闭 pstcGpioCfg.enCtrlMode = GpioFastIO; //< 端口输入/输出值寄存器总线控制模式配置->AHB Gpio_Init(DS18B20DQ_PORT, DS18B20DQ_PIN, &pstcGpioCfg); //初始化引脚 Gpio_WriteOutputIO(DS18B20DQ_PORT, DS18B20DQ_PIN,TRUE); ///< 默认置高电平 } static void DS18B20_IO_OUT(void) { stc_gpio_config_t pstcGpioCfg; DDL_ZERO_STRUCT(pstcGpioCfg); pstcGpioCfg.enDir = GpioDirOut; pstcGpioCfg.enDrv = GpioDrvH; //< 端口驱动能力配置->高驱动能力 pstcGpioCfg.enPuPd = GpioNoPuPd; //无上下拉 pstcGpioCfg.enOD = GpioOdDisable; //< 端口开漏输出配置->开漏输出关闭 pstcGpioCfg.enCtrlMode = GpioFastIO; //< 端口输入/输出值寄存器总线控制模式配置->AHB Gpio_Init(DS18B20DQ_PORT, DS18B20DQ_PIN, &pstcGpioCfg); //< 初始化引脚 Gpio_WriteOutputIO(DS18B20DQ_PORT, DS18B20DQ_PIN,FALSE);//< 默认置高电平 } static void DS18B20_IO_IN(void) { stc_gpio_config_t pstcGpioCfg; DDL_ZERO_STRUCT(pstcGpioCfg); pstcGpioCfg.enDir = GpioDirIn; pstcGpioCfg.enDrv = GpioDrvL; pstcGpioCfg.enPuPd = GpioNoPuPd; pstcGpioCfg.enOD = GpioOdDisable; pstcGpioCfg.enCtrlMode = GpioFastIO; Gpio_Init(DS18B20DQ_PORT, DS18B20DQ_PIN, &pstcGpioCfg); } //复位DS18B20 static void DS18B20_Rst(void) { DS18B20_IO_OUT(); ///< 配置端口输出 Gpio_WriteOutputIO(DS18B20DQ_PORT, DS18B20DQ_PIN,FALSE);///< 拉低DQ __delay_us__(DELAY_700US); ///< 拉低700us Gpio_WriteOutputIO(DS18B20DQ_PORT, DS18B20DQ_PIN,TRUE); ///< 拉高DQ __delay_us__(DELAY_15US); ///< 拉高15us } //等待DS18B20的回应 //返回1:未检测到DS18B20的存在 //返回0:存在 static uint8_t DS18B20_Check(void) { uint8_t retry = 0; DS18B20_IO_IN(); ///< 配置端口输入 while ((Gpio_GetInputIO(DS18B20DQ_PORT, DS18B20DQ_PIN) == 1) && (retry < 100)) ///< 最多200us { retry++; __delay_us__(DELAY_2US); ///< 每次等待2us } if (retry >= 200) { return 1; } else { retry = 0; } while ((Gpio_GetInputIO(DS18B20DQ_PORT, DS18B20DQ_PIN) == 0) && (retry < 120)) ///< 最多240us { retry++; __delay_us__(DELAY_2US); ///< 每次等待2us } if (retry >= 120) { return 1; } return 0; } //写一个字节到DS18B20 //dat:要写入的字节 static void DS18B20_Write_Byte(uint8_t dat) { uint8_t j; uint8_t testb; DS18B20_IO_OUT(); ///< 配置端口输出 for (j = 1; j <= 8; j++) { testb = dat & 0x01; dat = dat >> 1; if (testb) ///< 写入1 { Gpio_WriteOutputIO(DS18B20DQ_PORT, DS18B20DQ_PIN,FALSE); __delay_us__(DELAY_2US); ///< 拉低2us Gpio_WriteOutputIO(DS18B20DQ_PORT, DS18B20DQ_PIN,TRUE); __delay_us__(DELAY_60US); ///< 拉高64us } else ///< 写入0 { Gpio_WriteOutputIO(DS18B20DQ_PORT, DS18B20DQ_PIN,FALSE); __delay_us__(DELAY_60US); ///< 拉低64us Gpio_WriteOutputIO(DS18B20DQ_PORT, DS18B20DQ_PIN,TRUE); __delay_us__(DELAY_2US); ///< 拉高2us } } } //从DS18B20读取一个位 //返回值:1/0 static uint8_t DS18B20_Read_Bit(void) { uint8_t data; DS18B20_IO_OUT(); ///< 配置端口输出 Gpio_WriteOutputIO(DS18B20DQ_PORT, DS18B20DQ_PIN,FALSE); __delay_us__(DELAY_2US); ///< 等待2us Gpio_WriteOutputIO(DS18B20DQ_PORT, DS18B20DQ_PIN,TRUE); DS18B20_IO_IN(); ///< 配置端口输入 __delay_us__(DELAY_12US); ///< 等待12us if (Gpio_GetInputIO(DS18B20DQ_PORT, DS18B20DQ_PIN) == 1) { data = 1; } else { data = 0; } __delay_us__(DELAY_52US); ///< 等待52us return data; } //从DS18B20读取一个字节 //返回值:读到的数据 static uint8_t DS18B20_Read_Byte(void) { uint8_t i = 0, j = 0, dat = 0; uint8_t num1, num2; for (i = 1; i <= 8; i++) ///< 一次读取一个字节,8位 { j = DS18B20_Read_Bit(); num1 = j << 7; num2 = dat >> 1; dat = num1 | num2; } return dat; } // TL = DS18B20_Read_Byte(); ///< 读取LSB,低八位数据 // TH = DS18B20_Read_Byte(); ///< 读取MSB,高八位数据 //开始温度转换 static uint8_t DS18B20_Start(void) { DS18B20_Rst(); if (!DS18B20_Check()) { DS18B20_Write_Byte(0xCC); ///< skip rom DS18B20_Write_Byte(0x44); ///< convert return 0; } else { return 1; } } //读出温度 static float DS18B20_Read_Templet(void) { uint8_t TL = 0, TH = 0; uint16_t tem = 0; float temp = 0; uint8_t temp_flag = 0; //读取温度 DS18B20_Write_Byte(0xCC); ///< skip rom DS18B20_Write_Byte(0xBE); ///< convert TL = DS18B20_Read_Byte(); ///< 读取LSB,低八位数据 TH = DS18B20_Read_Byte(); ///< 读取MSB,高八位数据 if (TH > 7) ///< 温度为负 { TH = ~TH; TL = ~TL; temp_flag = 0; } else ///< 温度为正 { temp_flag = 1; } tem = TH; tem <<= 8; tem += TL; temp = (float)tem / 16.0; ///< 转换数据 if (temp_flag) { return temp; } return -temp; } float DS18B20_Get_Templet(void) { float fget_temp; uint8_t check_flag; check_flag = DS18B20_Start(); //1 if(!check_flag) { DS18B20_Rst(); //2 DS18B20_Check(); //3 fget_temp = DS18B20_Read_Templet(); //4 PRINTF_B20("DS18B20_Get_temp = %f", fget_temp); return fget_temp; } PRINTF_B20("DS18B20_Get_temp fail"); return 1; }
#ifndef __DS18B20__ #define __DS18B20__ #include "global.h" #define DS18B20DQ_PORT GpioPortB #define DS18B20DQ_PIN GpioPin8 extern uint8_t DS18B20_Init(void); //初始化管脚 extern float DS18B20_Get_Templet(void); //获取温度 #endif
//华大单片机时钟不准,最好做验证 //延时函数要准确,避免数据不准确 //如果有逻辑分析仪 可以自己做测试 //没有的话,我把我的内部时钟配置源码放在下面了,用我的时钟配置应该没问题 #define DELAY_700US 3694 #define DELAY_200US 1050 #define DELAY_150US 789 #define DELAY_60US 310 #define DELAY_52US 267 #define DELAY_15US 71 #define DELAY_12US 55 #define DELAY_2US 1 void __delay_us__(const uint32_t ucus) { register uint32_t ucustemp = ucus; while(ucustemp--) { __NOP(); } }
#define DEBUG_18B20 1 #if DEBUG_18B20 #define PRINTF_B20(format, ...) printf(format "\r\n", ##__VA_ARGS__ ) #else #define PRINTF_B20(format, ...) #endif
//时钟切换内部时钟48MHZ void SYSTEMCLKSWITCH(void) { stc_sysctrl_pll_config_t stcPLLCfg; stc_sysctrl_clk_config_t stcCfg; DDL_ZERO_STRUCT(stcPLLCfg); DDL_ZERO_STRUCT(stcCfg); Flash_WaitCycle(FlashWaitCycle1); //< 当前时钟源HCLK大于24M:此处设置FLASH 读等待周期为1 cycle(前面已经配置,此处无需重复配置) /*< 切换时钟前配置PLL相关参数*/ Sysctrl_SetRCHTrim(SysctrlRchFreq4MHz); //PLL使用RCH24MHz作为时钟源,因此需要先设置RCH,之前已经设置 Sysctrl_ClkSourceEnable(SysctrlClkRCH, TRUE); //RCH使能,因RCH使能未关闭,此处可以不重复操作 stcPLLCfg.enInFreq = SysctrlPllInFreq4_6MHz; //RCH 24MHz stcPLLCfg.enOutFreq = SysctrlPllOutFreq36_48MHz; //PLL 输出48MHz stcPLLCfg.enPllClkSrc = SysctrlPllRch; //输入时钟源选择RCH stcPLLCfg.enPllMul = SysctrlPllMul12; //4MHz x 12 = 48MHz Sysctrl_SetPLLFreq(&stcPLLCfg); ///< 选择PLL作为HCLK时钟源; stcCfg.enClkSrc = SysctrlClkPLL; stcCfg.enHClkDiv = SysctrlHclkDiv1; stcCfg.enPClkDiv = SysctrlPclkDiv1; Sysctrl_ClkInit(&stcCfg); Sysctrl_SetPLLStableTime(SysctrlPllStableCycle16384); Sysctrl_ClkSourceEnable(SysctrlClkPLL, TRUE); Sysctrl_SysClkSwitch(SysctrlClkPLL); //< 时钟切换 Sysctrl_ClkSourceEnable(SysctrlClkXTH, FALSE); //< 根据需要选择是否关闭原时钟(此处关闭XTH) }