初中生
最后登录1970-1-1
在线时间 小时
注册时间2021-12-23
|
硬件连接:DQ连接到PB7引脚,VCC连接5V, GND连接地(DQ的引脚可以在硬件宏中进行更改)
实验验证:利用外部中断发送信号量,进行温度采集,然后利用串口将温度信息进行打印,在实例中学习FreeRTOS的一些基本概念
一些问题:由于ds18b20需要使用微妙级定时,而FreeRTOS提供的vTaskDelay()提供的延时的最小精度是微秒级的,并且FreeRTOS使用了SysTick的中断,所以需要利用一个定时器来实现所需的微妙级定时,在此实例中,使用了TIM6,实现10us的定时,为什么不适用1us定时,因为当配置实现1us的定时的时候会出现,延时不准确的问题,具体原因还没有找到,如果实现1us定时器中断的朋友可以在下方评论,谢谢!
- #include "bsp_ds18b20.h"
- static uint8_t Read_Byte(void);
- static uint8_t Read_Bit(void);
- static void Write_Bit_1(void);
- static void Write_Bit_0(void);
- static void Write_Byte(uint8_t dat);
- static void DS_DIR_OUT(void);
- static void DS_DIR_IN(void);
- void Init_DS18B20(void)
- {
- uint8_t t = 0;
- DS_DIR_OUT(); //设置GPIO为推挽输出模式
- GPIO_SetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN);
- delay_10us(1);
- GPIO_ResetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN); //发送一个复位脉冲
- delay_10us(60); //延时>480us
- GPIO_SetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN); //拉高数据线
- delay_10us(5);
- DS_DIR_IN(); //设置GPIO口为上拉输入模式
- while (GPIO_ReadInputDataBit(DS18B20_DQ_PORT, DS18B20_DQ_PIN) == SET) //等待被拉低
- {
- delay_10us(1);
- t++;
- if (t>=240)
- {
- printf("DS18B20初始化失败\n");
- return ;
- }
- }
- t = 0;
- /* 等待总线被释放 */
- while (GPIO_ReadInputDataBit(DS18B20_DQ_PORT, DS18B20_DQ_PIN)==RESET && t<=240)
- {
- t++;
- delay_10us(1);
- }
- if (t>=240)
- printf("DS18B20初始化失败\n");
- // else
- // printf("DS18B20在线\n");
- }
- /**
- * [url=home.php?mod=space&uid=41770]@brief[/url] 向DS18B20写入一位0
- *
- */
- static void Write_Bit_0(void)
- {
- GPIO_ResetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN); //启动总线
- delay_10us(9); //在60us-120us之间
- GPIO_SetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN); //释放总线,0写入完成
- delay_10us(1); //至少1us
- }
- /**
- * @brief 向DS18B20写入一位1
- *
- */
- static void Write_Bit_1(void)
- {
- GPIO_ResetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN); //启动总线
- delay_10us(1); //大于1us
- GPIO_SetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN); //写入1
- delay_10us(5); //在15-60us之间
- }
- /**
- * @brief 单片机从DS18B20读一位
- *
- */
- static uint8_t Read_Bit(void)
- {
- uint8_t dat;
- /* 设置GPIO为输出模式 */
- DS_DIR_OUT();
- GPIO_ResetBits(DS18B20_DQ_PORT, DS18B20_DQ_PIN); //启动总线
- delay_10us(1); //大于1us
- DS_DIR_IN(); //设置为上拉输入模式,从GPIO读取数据
- if (GPIO_ReadInputDataBit(DS18B20_DQ_PORT, DS18B20_DQ_PIN)) //高电平返回1
- dat = 1;
- else //低电平返回0
- {
- dat = 0;
- }
- delay_10us(5);
-
- return dat;
- }
- /**
- * @brief 从DS18B20读取一个字节
- *
- */
- static uint8_t Read_Byte(void)
- {
- uint8_t i, dat=0;
- for (i=0; i<8; i++)
- {
- dat = dat | (Read_Bit()<<i); //DS18B20先传递低位
- }
- return dat;
- }
- /**
- * @brief 单片机向DS18B20写入一个字节
- *
- */
- static void Write_Byte(uint8_t dat)
- {
- uint8_t i=0;
- DS_DIR_OUT(); //设置GPIO为输出方向
- for(i=0; i<8; i++)
- {
- if (dat & (1<<i))
- Write_Bit_1();
- else
- Write_Bit_0();
- }
- }
- extern QueueHandle_t temperature;
- extern SemaphoreHandle_t startGetTemperature;
- void Read_Temperature(void)
- {
- uint8_t tempL, tempH;
- double temp;
-
- while (1)
- {
- xSemaphoreTake(startGetTemperature, portMAX_DELAY);
- Init_DS18B20(); //初始化DS18B20
- Write_Byte(0xCC); //跳过读取序列号操作
- Write_Byte(0x44); //启动温度转换
- /* 等待DS18B20温度转化完成 */
- while (Read_Bit()==0)
- {
- //delay_us(100000); //100ms
- delay_10us(10000);
- }
- Init_DS18B20(); //再次初始化DS18B20
- Write_Byte(0xCC);
- Write_Byte(0xBE); //读取温度寄存器
- tempL = Read_Byte(); //读取LSB
- tempH = Read_Byte(); //读取MSB
- if (tempH>0x7F) //最高位为1,则表示为负数
- {
- tempL = ~tempL; //???????
- tempH = ~tempH + 1;
- }
- temp = ( (tempH<<8) + tempL ) * 0.0625;
- xQueueSendToBack(temperature, &temp, portMAX_DELAY);
- }
- }
- /* 设置DS18B20为接收指令模式 */
- void DS_DIR_OUT(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_APB2PeriphClockCmd(DS18B20_CLK, ENABLE);
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Pin = DS18B20_DQ_PIN;
- GPIO_Init(DS18B20_DQ_PORT, &GPIO_InitStructure);
- }
- /* 设置DS18B20为发送数据模式 */
- void DS_DIR_IN(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_APB2PeriphClockCmd(DS18B20_CLK, ENABLE);
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
- GPIO_InitStructure.GPIO_Pin = DS18B20_DQ_PIN;
- GPIO_Init(DS18B20_DQ_PORT, &GPIO_InitStructure);
- }
- /**
- * @brief 读取DS18B20的64位CODE
- */
- void Read_DS18B20_Code(void)
- {
- uint8_t i;
- uint8_t code[4];
-
- /* 对DS18B20进行初始化 */
- Init_DS18B20();
- /* 读取CODE */
- Write_Byte(0x33);
- for (i=0; i<3; i++)
- {
- code[i] = Read_Byte();
- }
- printf("Code = %x%x%x%x\n", code[3], code[2], code[1], code[0]);
- }
- /**
- * @brief 设置DS18B20进行警报的上下界
- *
- */
- void Set_DS18B20_Alarm(int8_t th, int8_t tl)
- {
- /* 对DS18B20进行初始化 */
- Init_DS18B20();
- /* 跳过对DS18B20的寻址 */
- Write_Byte(0xCC);
- /* 准备对2,3字节写入数据 */
- Write_Byte(0x4E);
- /* 对2,3字节写入数据 */
- Write_Byte(th);
- Write_Byte(tl);
- Write_Byte(0x7F); //设置12bit
- }
- /**
- * @brief 读取DS18B20寄存器中的数据
- *
- */
- void Read_DS18B20_Data(void)
- {
- uint8_t i;
- Init_DS18B20();
- Write_Byte(0xCC);
- Write_Byte(0xBE);
- for(i=0; i<9; i++)
- {
- printf("Byte%d: %x\n", i, Read_Byte());
- }
- }
复制代码 ds18b20.h
- /****************************
- * DS18B20的驱动程序
- * 条件
- 需要实现 void delay_us(uint32_t delay),实现delay微秒的定时
- ****************************/
- #ifndef BSP_DS18B20_H_
- #define BSP_DS18B20_H_
- #include "stm32f10x.h"
- #include "FreeRTOS.h"
- #include "semphr.h"
- #include "queue.h"
- #include "task.h"
- #include <stdio.h>
- /* 硬件端口的相关定义 */
- #define DS18B20_DQ_PORT GPIOB
- #define DS18B20_DQ_PIN GPIO_Pin_7
- #define DS18B20_CLK RCC_APB2Periph_GPIOA
- /* 使用到的函数定义 */
- void Init_DS18B20(void); //对DS18B20进行初始化
- void Read_Temperature(void); //读取温度
- void Read_DS18B20_Code(void); //读取DS18B20的64位CODE码
- void Set_DS18B20_Alarm(int8_t th, int8_t tl);
- void Read_DS18B20_Data(void); //读取寄存器中的数据
- extern void delay_10us(uint32_t);
- #endif
复制代码
main.c
- /**************************************
- * 功能:利用ds18b20来联系FreeRTOS中的队列,互斥量,任务创建
- * 将ds18b20读取的数据放入队列中,然后显示函数将温度数据
- * 发送到串口进行显示,同时在外部中断中使用互斥量来控制
- * 是否进行温度的采集,每按下一次进行一次温度采集,并显
- * 示
- *
- *
- * ***********************************/
- #include "FreeRTOS.h"
- #include "task.h"
- #include "semphr.h"
- #include "queue.h"
- #include "bsp_key.h"
- #include "bsp_led.h"
- #include "bsp_usart.h"
- #include "bsp_ds18b20.h"
- #include "stm32f10x_tim.h"
- #ifndef TRURE
- #define TRUE 1
- #endif
- /*--------------------全局变量声明------------------------------------------------*/
- /* 所用使用到的句柄 */
- TaskHandle_t getTemperature;
- TaskHandle_t taskCompHandle;
- /* 用来声明一个全局变量,来检测返回结果 */
- BaseType_t xReturn;
- volatile uint32_t delay;
- //任务将传递数据
- QueueHandle_t temperature;
- //二值信号量用来同步
- SemaphoreHandle_t startGetTemperature;
- /*----------------------------------------------------------------------------------*/
- /* 函数声明 */
- static void BSP_Init(void);
- void Show_Temeprature(void* pvParameter);
- void Open_Timer6(void);
- void Show_Message(void);
- void delay_10us(uint32_t);
- int main(void)
- {
- /* 硬件资源初始化 */
- BSP_Init();
-
- temperature = xQueueCreate(1, sizeof(double));
- startGetTemperature = xSemaphoreCreateBinary();
- /* 进行互斥量初始化有效 */
- xSemaphoreGive(startGetTemperature);
-
- xReturn = xTaskCreate((TaskFunction_t)Read_Temperature,
- (const char*)"Read_Temp",
- 128,
- NULL,
- 2,
- &getTemperature);
- printf("获取温度任务创建成功\n");
- xReturn = xTaskCreate((TaskFunction_t)Show_Temeprature,
- (const char*)"taskComp",
- 128,
- NULL,
- 3,
- &taskCompHandle);
- printf("显示温度任务创建成功\n");
- vTaskStartScheduler();
- while(TRUE);
- }
- void Show_Temeprature(void* pvParameter)
- {
- double tem;
- while (1)
- {
- xReturn = xQueueReceive(temperature, &tem, pdMS_TO_TICKS(1000));
- if (xReturn==pdPASS)
- {
- printf("温度为: %lf\n", tem);
- }
- }
- }
- static void BSP_Init(void)
- {
- NVIC_InitTypeDef NVIC_InitStructure;
- /* 中断部分配置 */
- NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
- NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; //定时器6
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- /* 进行中断初始化 */
- NVIC_Init(&NVIC_InitStructure);
- /* LED初始化 */
- LED_GPIO_Config();
- /* KEY初始化 */
- //KEY_Init();
- ExternalInterruptOfKey1_Init();
- /* 测试硬件是否正常工作 */
- LED_RGBOFF;
- /* 打开基本定时器6中断 */
- Open_Timer6();
- /* 让程序停在这里,不再继续往下执行 */
- //while (1);
- /* 串口初始化 */
- USART_Config();
- }
- void Open_Timer6(void)
- {
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); //打开TIMER6的时钟
- TIM_TimeBaseInitStructure.TIM_Prescaler = 8; //分频之后频率为9MHz = 72/(8+1)
- TIM_TimeBaseInitStructure.TIM_Period = 90; //实现10us的定时
- /* 其余的定时器配置,对于基础定时器来说不需要进行配置 */
- TIM_TimeBaseInit(TIM6, &TIM_TimeBaseInitStructure);
- /* 清除计数器中断标志位 */
- TIM_ClearFlag(TIM6, TIM_FLAG_Update);
- /* 打开定时器中断 */
- TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
- /* 使能计数器 */
- TIM_Cmd(TIM6, ENABLE);
- }
- void delay_10us(uint32_t delayDat)
- {
- delay = delayDat;
- while(delay!=0);
- }
复制代码 mdk工程文件
|
|