[STM32F1] VSCODE STM32 裸机之DS18B20

[复制链接]
2192|2
 楼主| zero949079783 发表于 2021-10-23 22:36 | 显示全部楼层 |阅读模式
本帖最后由 zero949079783 于 2021-10-27 09:19 编辑

开发环境:VSCODE(gcc编译链)+STM32CubeMX(也可以使用HUAWEI-LiteOS-Studio) 。
代码:链接:https://pan.baidu.com/s/1uXfIR0GFQOBZPl1NfQP08w  
提取码:6b0c


DS18B20的工作时序:

1.png
初始化时序
主机首先发出一个480-960微秒的低电平脉冲,然后释放总线变为高电平,并在随后的480微秒时间内对总线进行检测,如果有低电平出现说明总线上有器件已做出应答。
若无低电平出现一直都是高电平说明总线上无器件应答。
做为从器件的DS18B20在一上电后就一直在检测总线上是否有480-960微秒的低电平出现,如果有,在总线转为高电平后等待15-60微秒后将总线电平拉低60-240微秒做出响应存在脉冲,告诉主机本器件已做好准备。若没有检测到就一直在检测等待。

复位代码:
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]   复位DS18B20
  3.   * @param  
  4.   *     @arg
  5.   * @retval  dat :返回1:未检测到DS18B20的存在 返回0:存在
  6.   */
  7. uint8_t DS18B20_Rst(void)
  8. {
  9.     uint8_t dat;
  10.     DS18B20_Write_Out_Input(DS18B20_WRITE); //设为输出
  11.     DS18B20_OUT_L();
  12.     delay_us(48); //480us
  13.     DS18B20_OUT_H();
  14.     delay_us(6); //60us
  15.     DS18B20_Write_Out_Input(DS18B20_READ);//设为输入
  16.     dat =  DS18B20_IN();
  17.     delay_us(48); //480us

  18.     return dat;

  19. }

  20. /**
  21.   * [url=home.php?mod=space&uid=247401]@brief[/url]   DS18B20 IO方向设置 输出输出
  22.   * @param  cmd :DS18B20_WRITE /DS18B20_READ
  23.   *     @arg
  24.   * @retval  无
  25.   */
  26. void DS18B20_Write_Out_Input(uint8_t cmd)
  27. {
  28.     GPIO_InitTypeDef GPIO_InitStruct = {0};
  29.     if(cmd == DS18B20_WRITE )
  30.     {
  31.         GPIO_InitStruct.Pin = DS18B20_Pin;
  32.         GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  33.         GPIO_InitStruct.Pull = GPIO_PULLUP;
  34.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  35.         HAL_GPIO_Init(DS18B20_GPIO_Port, &GPIO_InitStruct);
  36.     }

  37.     else
  38.   {
  39.         GPIO_InitStruct.Pin = DS18B20_Pin;
  40.         GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  41.         HAL_GPIO_Init(DS18B20_GPIO_Port, &GPIO_InitStruct);
  42.     }
  43. }







2.png
写操作
写周期最少为60微秒,最长不超过120微秒。写周期一开始做为主机先把总线拉低1微秒表示写周期开始。随后若主机想写0,则继续拉低电平最少60微秒直至写周期结束,然后释放总线为高电平。若主机想写1,在一开始拉低总线电平1微秒后就释放总线为高电平,一直到写周期结束。而做为从机的DS18B20则在检测到总线被拉底后等待15微秒然后从15us到45us开始对总线采样,在采样期内总线为高电平则为1,若采样期内总线为低电平则为0。
写操作
  1. /**
  2.   * @brief  写一个字节到DS18B20
  3.   * @param  dat:要写入的字节
  4.   *     @arg
  5.   * @retval  
  6.   */
  7. void DS18B20_Write_Byte(uint8_t dat)
  8. {
  9.     uint8_t i;
  10.     for(i=0;i<8;i++)
  11.     {
  12.         DS18B20_Write_Out_Input(DS18B20_WRITE);
  13.         DS18B20_OUT_L();
  14.         delay_us(2);

  15.         if(dat &0x01)  
  16.             DS18B20_OUT_H();//写1
  17.         else
  18.             DS18B20_OUT_L();//写0

  19.         delay_us(6);

  20.         DS18B20_OUT_H();

  21.         dat >>=1;
  22.     }

  23. }


3.png
读操作
对于读数据操作时序也分为读0时序和读1时序两个过程。读时隙是从主机把单总线拉低之后,在1微秒之后就得释放单总线为高电平,以让DS18B20把数据传输到单总线上。DS18B20在检测到总线被拉低1微秒后,便开始送出数据,若是要送出0就把总线拉为低电平直到读周期结束。若要送出1则释放总线为高电平。主机在一开始拉低总线1微秒后释放总线,然后在包括前面的拉低总线电平1微秒在内的15微秒时间内完成对总线进行采样检测,采样期内总线为低电平则确认为0。采样期内总线为高电平则确认为1。完成一个读时序过程,至少需要60us才能完成
读操作代码:
  1. /**
  2.   * @brief  从DS18B20读取一个字节
  3.   * @param  
  4.   *     @arg
  5.   * @retval  读到的数据
  6.   */
  7. uint8_t DS18B20_Read_Byte(void)
  8. {
  9.     uint8_t dat=0,i;

  10.     for(i=0;i<8;i++)
  11.     {
  12.         DS18B20_Write_Out_Input(DS18B20_WRITE);
  13.         DS18B20_OUT_L();
  14.         delay_us(2);
  15.         DS18B20_OUT_H(); //总线释放
  16.         dat >>=1;
  17.         DS18B20_Write_Out_Input(DS18B20_READ);
  18.         if(DS18B20_IN() == 1){
  19.             dat |=0x80;
  20.         }
  21.         else{
  22.             dat &=0x7F;
  23.         }
  24.         delay_us(6);               
  25.     }

  26.         return dat;
  27. }



读取RAM内的温度数据。同样,这个操作也要接照三个步骤。

1、主机发出复位操作并接收DS18B20的应答(存在)脉冲。

2、主机发出跳过对ROM操作的命令(CCH)。

3、主机发出读取RAM的命令(BEH),随后主机依次读取DS18B20发出的从第0一第8,共九个字节的数据。如果只想读取温度数据,那在读完第0和第1个数据后就不再理会后面DS18B20发出的数据即可。同样读取数据也是低位在前的。

  1. //开始温度转换
  2. float DS18B20_Get_Temp(void)
  3. {
  4.     uint8_t MSB =0 ,MSL=0;
  5.     uint16_t Temp=0;
  6.     float Ftemp = 0;

  7.     if(DS18B20_Rst() == 0){
  8.         DS18B20_Rst();
  9.         DS18B20_Write_Byte(0XCC); //跳过ROM
  10.         DS18B20_Write_Byte(0X44);
  11.         delay_ms(750);
  12.         DS18B20_Rst();
  13.         DS18B20_Write_Byte(0XCC); //跳过ROM
  14.         DS18B20_Write_Byte(0XBE);

  15.         MSL = DS18B20_Read_Byte(); //低8位
  16.         MSB = DS18B20_Read_Byte(); //高8位

  17.         Temp = MSB;
  18.         Temp = (Temp<<8) |MSL;

  19.         if((Temp&0xf800) == 0xf800){ //1111 1000 0000 0000   前5为1,为负温度
  20.             Temp = (((~Temp) + 0X01) * -0.0625);
  21.         }
  22.         else{
  23.             Ftemp =Temp *0.0625;
  24.             //Temp = Ftemp *100+0.5;
  25.         }
  26.     }
  27.     else{
  28.         printf("DS18B20 未检测到 \n\r");
  29.     }

  30.     return Ftemp;
  31. }




微秒延时函数:
  1. #include "delay.h"
  2. #include "core_cm3.h"


  3. static __IO uint32_t TimingDelay;

  4. /**
  5.   * @brief  启动系统滴答定时器 SysTick
  6.   * @param  无
  7.   * @retval 无
  8.   */
  9. void SysTick_Init(void)
  10. {
  11.     /* SystemFrequency / 1000    1ms中断一次
  12.      * SystemFrequency / 100000  10us中断一次
  13.      * SystemFrequency / 1000000 1us中断一次
  14.      */
  15. //  if (SysTick_Config(SystemFrequency / 100000))   // ST3.0.0库版本
  16.     if (SysTick_Config(SystemCoreClock / 100000))   // ST3.5.0库版本 //HAL库只能使用10us中断一次
  17.     {
  18.         /* Capture error */
  19.         while (1);
  20.     }
  21. }

  22. /**
  23.   * @brief   us延时程序,1us为一个单位
  24.   * @param  
  25.   *     [url=home.php?mod=space&uid=2817080]@ARG[/url] nTime: Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
  26.   * @retval  无
  27.   */
  28. void delay_us(__IO uint32_t nTime)
  29. {
  30.     TimingDelay = nTime;   

  31.     // 使能滴答定时器  
  32.     SysTick->CTRL |=  SysTick_CTRL_ENABLE_Msk;

  33.     while(TimingDelay != 0);
  34. }

  35. /**
  36.   * @brief  获取节拍程序
  37.   * @param  无
  38.   * @retval 无
  39.   * [url=home.php?mod=space&uid=93590]@Attention[/url]  在 SysTick 中断函数 SysTick_Handler()调用
  40.   */
  41. void TimingDelay_Decrement(void)
  42. {
  43.     if (TimingDelay != 0x00)
  44.     {
  45.         TimingDelay--;
  46.     }
  47. }

  48. #if 0
  49. // 这个 固件库函数 在 core_cm3.h中
  50. static __INLINE uint32_t SysTick_Config(uint32_t ticks)
  51. {
  52.   // reload 寄存器为24bit,最大值为2^24
  53.     if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);
  54.   
  55.   // 配置 reload 寄存器的初始值  
  56.   SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
  57.    
  58.     // 配置中断优先级为 1<<4-1 = 15,优先级为最低
  59.   NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
  60.    
  61.     // 配置 counter 计数器的值
  62.   SysTick->VAL   = 0;
  63.    
  64.     // 配置systick 的时钟为 72M
  65.     // 使能中断
  66.     // 使能systick
  67.   SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
  68.                    SysTick_CTRL_TICKINT_Msk   |
  69.                    SysTick_CTRL_ENABLE_Msk;                    
  70.   return (0);
  71. }
  72. #endif

  73. // couter 减1的时间 等于 1/systick_clk
  74. // 当counter 从 reload 的值减小到0的时候,为一个循环,如果开启了中断则执行中断服务程序,
  75. // 同时 CTRL 的 countflag 位会置1
  76. // 这一个循环的时间为 reload * (1/systick_clk)

  77. void SysTick_Delay_Us( __IO uint32_t us)
  78. {
  79.     uint32_t i;
  80.     SysTick_Config(SystemCoreClock/1000000);

  81.     for(i=0;i<us;i++)
  82.     {
  83.         // 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
  84.         while( !((SysTick->CTRL)&(1<<16)) );
  85.     }
  86.     // 关闭SysTick定时器
  87.     SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;
  88. }

  89. void SysTick_Delay_Ms( __IO uint32_t ms)
  90. {
  91.     uint32_t i;
  92.     SysTick_Config(SystemCoreClock/1000);

  93.     for(i=0;i<ms;i++)
  94.     {
  95.         // 当计数器的值减小到0的时候,CRTL寄存器的位16会置1
  96.         // 当置1时,读取该位会清0
  97.         while( !((SysTick->CTRL)&(1<<16)) );
  98.     }
  99.     // 关闭SysTick定时器
  100.     SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
  101. }



  102. //static uint8_t fac_us = RESET;
  103. //static uint16_t fac_ms = RESET;

  104. //void delay_UserConfig(uint8_t SYSCLK)
  105. //{
  106. //  SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //8分频 72/8=9
  107. //  fac_us = SYSCLK /8;//计数 9个数
  108. //  fac_ms = (uint16_t)fac_us *1000; //1S= 1000MS *9=9000  1ms= 1000us*9 =9000
  109. //}


  110. //void delay_ms(uint16_t ms)
  111. //{
  112. //  uint32_t temp;
  113. //  SysTick ->LOAD = fac_ms*ms; // 重载
  114. //  SysTick ->VAL = 0x00; //清空
  115. //  SysTick ->CTRL |= SysTick_CTRL_ENABLE_Msk;//开启定时器
  116. //  
  117. //  do
  118. //  {
  119. //      temp = SysTick ->CTRL;
  120. //  }
  121. //  while((temp&0x01) &&!(temp&(1<<16)));//COUNTFLAG==1
  122. //  SysTick ->VAL =0X00;
  123. //  SysTick ->CTRL &= ~SysTick_CTRL_ENABLE_Msk;//关闭定时器
  124. //}

  125. //void delay_us(uint32_t us)
  126. //{
  127. //  uint32_t temp;
  128. //  SysTick ->LOAD = fac_us*us; // 重载
  129. //  SysTick ->VAL = 0x00; //清空
  130. //  SysTick ->CTRL |= SysTick_CTRL_ENABLE_Msk;//开启定时器
  131. //  
  132. //  do
  133. //  {
  134. //      temp = SysTick ->CTRL;
  135. //  }
  136. //  while((temp&0x01) &&!(temp&(1<<16)));//COUNTFLAG==1
  137. //  SysTick ->VAL =0X00;
  138. //  SysTick ->CTRL &= ~SysTick_CTRL_ENABLE_Msk;//关闭定时器

  139. //}








  
小叶三千 发表于 2021-10-26 08:17 | 显示全部楼层
感谢分享,不过代码贴的有点问题啊,看着不是很舒服,应该用代码格式
 楼主| zero949079783 发表于 2021-10-26 19:46 | 显示全部楼层
小叶三千 发表于 2021-10-26 08:17
感谢分享,不过代码贴的有点问题啊,看着不是很舒服,应该用代码格式

您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

91

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部