野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 3893|回复: 0

[freertos] 利用温度采集系统实例来学习FreeRTOS的一些基本概念

[复制链接]
发表于 2022-5-26 15:53:18 | 显示全部楼层 |阅读模式
硬件连接:DQ连接到PB7引脚,VCC连接5V, GND连接地(DQ的引脚可以在硬件宏中进行更改)

实验验证:利用外部中断发送信号量,进行温度采集,然后利用串口将温度信息进行打印,在实例中学习FreeRTOS的一些基本概念

一些问题:由于ds18b20需要使用微妙级定时,而FreeRTOS提供的vTaskDelay()提供的延时的最小精度是微秒级的,并且FreeRTOS使用了SysTick的中断,所以需要利用一个定时器来实现所需的微妙级定时,在此实例中,使用了TIM6,实现10us的定时,为什么不适用1us定时,因为当配置实现1us的定时的时候会出现,延时不准确的问题,具体原因还没有找到,如果实现1us定时器中断的朋友可以在下方评论,谢谢!

  1. #include "bsp_ds18b20.h"

  2. static uint8_t Read_Byte(void);
  3. static uint8_t Read_Bit(void);
  4. static void Write_Bit_1(void);
  5. static void Write_Bit_0(void);
  6. static void Write_Byte(uint8_t dat);
  7. static void DS_DIR_OUT(void);
  8. static void DS_DIR_IN(void);


  9. void Init_DS18B20(void)
  10. {
  11.         uint8_t t = 0;
  12.         DS_DIR_OUT();        //设置GPIO为推挽输出模式
  13.         GPIO_SetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN);
  14.         delay_10us(1);
  15.         GPIO_ResetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN);        //发送一个复位脉冲
  16.         delay_10us(60);                //延时>480us
  17.         GPIO_SetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN);                //拉高数据线
  18.         delay_10us(5);
  19.         DS_DIR_IN();        //设置GPIO口为上拉输入模式
  20.         while (GPIO_ReadInputDataBit(DS18B20_DQ_PORT, DS18B20_DQ_PIN) == SET)        //等待被拉低
  21.         {
  22.                 delay_10us(1);
  23.                 t++;
  24.                 if (t>=240)
  25.                 {
  26.                         printf("DS18B20初始化失败\n");
  27.                         return ;
  28.                 }
  29.         }

  30.         t = 0;

  31.         /* 等待总线被释放 */
  32.         while (GPIO_ReadInputDataBit(DS18B20_DQ_PORT, DS18B20_DQ_PIN)==RESET && t<=240)
  33.         {
  34.                 t++;
  35.                 delay_10us(1);
  36.         }
  37.         if (t>=240)
  38.                 printf("DS18B20初始化失败\n");
  39. //        else
  40. //                printf("DS18B20在线\n");
  41. }

  42. /**
  43. * [url=home.php?mod=space&uid=41770]@brief[/url] 向DS18B20写入一位0
  44. *
  45. */
  46. static void Write_Bit_0(void)
  47. {
  48.         GPIO_ResetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN);        //启动总线
  49.         delay_10us(9);                                                //在60us-120us之间
  50.         GPIO_SetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN);                //释放总线,0写入完成
  51.         delay_10us(1);                                                //至少1us
  52. }

  53. /**
  54. * @brief 向DS18B20写入一位1
  55. *
  56. */

  57. static void Write_Bit_1(void)
  58. {
  59.         GPIO_ResetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN);        //启动总线
  60.         delay_10us(1);                                                //大于1us
  61.         GPIO_SetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN);                //写入1
  62.         delay_10us(5);                                                //在15-60us之间
  63. }

  64. /**
  65. * @brief 单片机从DS18B20读一位
  66. *
  67. */
  68. static uint8_t Read_Bit(void)
  69. {
  70.         uint8_t dat;
  71.         /* 设置GPIO为输出模式 */
  72.         DS_DIR_OUT();
  73.         GPIO_ResetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN);        //启动总线
  74.         delay_10us(1);                                                //大于1us
  75.         DS_DIR_IN();                                                //设置为上拉输入模式,从GPIO读取数据

  76.         if (GPIO_ReadInputDataBit(DS18B20_DQ_PORT, DS18B20_DQ_PIN))        //高电平返回1
  77.                 dat = 1;
  78.         else                                                                //低电平返回0
  79.         {
  80.                 dat = 0;
  81.         }

  82.         delay_10us(5);
  83.        
  84.         return dat;       
  85. }

  86. /**
  87. * @brief 从DS18B20读取一个字节
  88. *
  89. */
  90. static uint8_t Read_Byte(void)
  91. {
  92.         uint8_t i, dat=0;

  93.         for (i=0; i<8; i++)
  94.         {
  95.                 dat = dat | (Read_Bit()<<i);        //DS18B20先传递低位
  96.         }
  97.         return dat;
  98. }


  99. /**
  100. * @brief 单片机向DS18B20写入一个字节
  101. *
  102. */

  103. static void Write_Byte(uint8_t dat)
  104. {
  105.         uint8_t i=0;
  106.         DS_DIR_OUT();                //设置GPIO为输出方向

  107.         for(i=0; i<8; i++)
  108.         {
  109.                 if (dat & (1<<i))
  110.                         Write_Bit_1();
  111.                 else
  112.                         Write_Bit_0();
  113.         }
  114. }

  115. extern QueueHandle_t temperature;
  116. extern SemaphoreHandle_t startGetTemperature;

  117. void Read_Temperature(void)
  118. {
  119.         uint8_t tempL, tempH;
  120.         double temp;
  121.        
  122.         while (1)
  123.         {
  124.                 xSemaphoreTake(startGetTemperature, portMAX_DELAY);       

  125.                 Init_DS18B20();                //初始化DS18B20
  126.                 Write_Byte(0xCC);        //跳过读取序列号操作
  127.                 Write_Byte(0x44);        //启动温度转换

  128.                 /* 等待DS18B20温度转化完成 */
  129.                 while (Read_Bit()==0)
  130.                 {
  131.                         //delay_us(100000);        //100ms
  132.                         delay_10us(10000);
  133.                 }
  134.                 Init_DS18B20();                //再次初始化DS18B20
  135.                 Write_Byte(0xCC);       
  136.                 Write_Byte(0xBE);        //读取温度寄存器
  137.                 tempL = Read_Byte();        //读取LSB
  138.                 tempH = Read_Byte();        //读取MSB

  139.                 if (tempH>0x7F)                //最高位为1,则表示为负数
  140.                 {
  141.                         tempL = ~tempL;        //???????
  142.                         tempH = ~tempH + 1;
  143.                 }
  144.                 temp = ( (tempH<<8) + tempL ) * 0.0625;
  145.                 xQueueSendToBack(temperature, &temp, portMAX_DELAY);
  146.         }
  147. }

  148. /* 设置DS18B20为接收指令模式 */
  149. void DS_DIR_OUT(void)
  150. {
  151.         GPIO_InitTypeDef GPIO_InitStructure;

  152.         RCC_APB2PeriphClockCmd(DS18B20_CLK, ENABLE);

  153.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  154.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  155.         GPIO_InitStructure.GPIO_Pin = DS18B20_DQ_PIN;

  156.         GPIO_Init(DS18B20_DQ_PORT, &GPIO_InitStructure);
  157. }

  158. /* 设置DS18B20为发送数据模式 */
  159. void DS_DIR_IN(void)
  160. {
  161.         GPIO_InitTypeDef GPIO_InitStructure;

  162.         RCC_APB2PeriphClockCmd(DS18B20_CLK, ENABLE);

  163.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  164.         GPIO_InitStructure.GPIO_Pin = DS18B20_DQ_PIN;

  165.         GPIO_Init(DS18B20_DQ_PORT, &GPIO_InitStructure);
  166. }

  167. /**
  168.         * @brief 读取DS18B20的64位CODE
  169.         */

  170. void Read_DS18B20_Code(void)
  171. {
  172.         uint8_t i;
  173.         uint8_t code[4];
  174.        
  175.         /* 对DS18B20进行初始化 */
  176.         Init_DS18B20();
  177.         /* 读取CODE */
  178.         Write_Byte(0x33);
  179.         for (i=0; i<3; i++)
  180.         {
  181.                 code[i] = Read_Byte();
  182.         }
  183.         printf("Code = %x%x%x%x\n", code[3], code[2], code[1], code[0]);
  184. }

  185. /**
  186. * @brief 设置DS18B20进行警报的上下界
  187. *
  188. */

  189. void Set_DS18B20_Alarm(int8_t th, int8_t tl)
  190. {
  191.         /* 对DS18B20进行初始化 */
  192.         Init_DS18B20();
  193.         /* 跳过对DS18B20的寻址 */
  194.         Write_Byte(0xCC);
  195.         /* 准备对2,3字节写入数据 */
  196.         Write_Byte(0x4E);
  197.         /* 对2,3字节写入数据 */
  198.         Write_Byte(th);
  199.         Write_Byte(tl);
  200.         Write_Byte(0x7F);        //设置12bit
  201. }

  202. /**
  203. * @brief 读取DS18B20寄存器中的数据
  204. *
  205. */

  206. void Read_DS18B20_Data(void)
  207. {
  208.         uint8_t i;
  209.         Init_DS18B20();
  210.         Write_Byte(0xCC);
  211.         Write_Byte(0xBE);

  212.         for(i=0; i<9; i++)
  213.         {
  214.                 printf("Byte%d: %x\n", i, Read_Byte());
  215.         }
  216. }
复制代码
ds18b20.h
  1. /****************************

  2.         * DS18B20的驱动程序
  3.         * 条件
  4.                                 需要实现 void delay_us(uint32_t delay),实现delay微秒的定时

  5. ****************************/


  6. #ifndef BSP_DS18B20_H_
  7. #define BSP_DS18B20_H_


  8. #include "stm32f10x.h"
  9. #include "FreeRTOS.h"
  10. #include "semphr.h"
  11. #include "queue.h"
  12. #include "task.h"
  13. #include <stdio.h>

  14. /* 硬件端口的相关定义 */
  15. #define DS18B20_DQ_PORT        GPIOB
  16. #define DS18B20_DQ_PIN GPIO_Pin_7
  17. #define DS18B20_CLK        RCC_APB2Periph_GPIOA

  18. /* 使用到的函数定义 */

  19. void Init_DS18B20(void);                                        //对DS18B20进行初始化
  20. void Read_Temperature(void);                                        //读取温度
  21. void Read_DS18B20_Code(void);                                        //读取DS18B20的64位CODE码
  22. void Set_DS18B20_Alarm(int8_t th, int8_t tl);
  23. void Read_DS18B20_Data(void);                //读取寄存器中的数据


  24. extern void delay_10us(uint32_t);

  25. #endif
复制代码

main.c
  1. /**************************************
  2. *  功能:利用ds18b20来联系FreeRTOS中的队列,互斥量,任务创建
  3. *      将ds18b20读取的数据放入队列中,然后显示函数将温度数据
  4. *      发送到串口进行显示,同时在外部中断中使用互斥量来控制
  5. *      是否进行温度的采集,每按下一次进行一次温度采集,并显
  6. *      示
  7. *
  8. *
  9. * ***********************************/
  10. #include "FreeRTOS.h"
  11. #include "task.h"
  12. #include "semphr.h"
  13. #include "queue.h"
  14. #include "bsp_key.h"
  15. #include "bsp_led.h"
  16. #include "bsp_usart.h"
  17. #include "bsp_ds18b20.h"
  18. #include "stm32f10x_tim.h"

  19. #ifndef TRURE
  20.     #define TRUE 1
  21. #endif

  22. /*--------------------全局变量声明------------------------------------------------*/

  23. /* 所用使用到的句柄 */
  24. TaskHandle_t getTemperature;
  25. TaskHandle_t taskCompHandle;


  26. /* 用来声明一个全局变量,来检测返回结果 */
  27. BaseType_t          xReturn;
  28. volatile uint32_t   delay;
  29. //任务将传递数据
  30. QueueHandle_t       temperature;
  31. //二值信号量用来同步
  32. SemaphoreHandle_t   startGetTemperature;



  33. /*----------------------------------------------------------------------------------*/

  34. /* 函数声明 */
  35. static void BSP_Init(void);
  36. void Show_Temeprature(void* pvParameter);
  37. void Open_Timer6(void);
  38. void Show_Message(void);
  39. void  delay_10us(uint32_t);

  40. int main(void)
  41. {
  42.     /* 硬件资源初始化 */
  43.     BSP_Init();
  44.    
  45.     temperature = xQueueCreate(1, sizeof(double));
  46.     startGetTemperature = xSemaphoreCreateBinary();

  47.     /* 进行互斥量初始化有效 */
  48.     xSemaphoreGive(startGetTemperature);
  49.        
  50.         xReturn = xTaskCreate((TaskFunction_t)Read_Temperature,
  51.                                                                                                 (const char*)"Read_Temp",
  52.                                                                                                 128,
  53.                                                                                                 NULL,
  54.                                                                                                 2,
  55.                                                                                                 &getTemperature);
  56.     printf("获取温度任务创建成功\n");

  57.         xReturn = xTaskCreate((TaskFunction_t)Show_Temeprature,
  58.                                                                                                 (const char*)"taskComp",
  59.                                                                                                 128,
  60.                                                                                                 NULL,
  61.                                                                                                 3,
  62.                                                                                                 &taskCompHandle);
  63.     printf("显示温度任务创建成功\n");

  64.     vTaskStartScheduler();
  65.     while(TRUE);

  66. }

  67. void Show_Temeprature(void* pvParameter)
  68. {
  69.     double tem;
  70.         while (1)
  71.         {
  72.         xReturn = xQueueReceive(temperature, &tem, pdMS_TO_TICKS(1000));
  73.         if (xReturn==pdPASS)
  74.         {
  75.             printf("温度为: %lf\n", tem);
  76.         }
  77.         }
  78. }


  79. static void BSP_Init(void)
  80. {
  81.     NVIC_InitTypeDef NVIC_InitStructure;

  82.     /* 中断部分配置 */
  83.     NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );

  84.     NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;     //定时器6
  85.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  86.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  87.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  88.     /* 进行中断初始化 */
  89.     NVIC_Init(&NVIC_InitStructure);

  90.     /* LED初始化 */
  91.     LED_GPIO_Config();
  92.     /* KEY初始化 */
  93.     //KEY_Init();
  94.     ExternalInterruptOfKey1_Init();

  95.     /* 测试硬件是否正常工作 */
  96.     LED_RGBOFF;

  97.     /* 打开基本定时器6中断 */
  98.     Open_Timer6();

  99.     /* 让程序停在这里,不再继续往下执行 */
  100.     //while (1);


  101.     /* 串口初始化 */
  102.     USART_Config();
  103. }

  104. void Open_Timer6(void)
  105. {
  106.    TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStructure;

  107.    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);          //打开TIMER6的时钟

  108.    TIM_TimeBaseInitStructure.TIM_Prescaler = 8;    //分频之后频率为9MHz = 72/(8+1)
  109.    TIM_TimeBaseInitStructure.TIM_Period = 90;           //实现10us的定时

  110.    /* 其余的定时器配置,对于基础定时器来说不需要进行配置 */
  111.    TIM_TimeBaseInit(TIM6, &TIM_TimeBaseInitStructure);

  112.    /* 清除计数器中断标志位 */
  113.    TIM_ClearFlag(TIM6, TIM_FLAG_Update);

  114.    /* 打开定时器中断 */
  115.    TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);

  116.    /* 使能计数器 */
  117.    TIM_Cmd(TIM6, ENABLE);

  118. }

  119. void delay_10us(uint32_t delayDat)
  120. {
  121.     delay = delayDat;
  122.     while(delay!=0);
  123. }

复制代码
mdk工程文件



ds18b20测试.zip

8.38 MB, 下载次数: 17

回复

使用道具 举报

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

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-11-21 23:30 , Processed in 0.029242 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表