FreeRTOS结合MX软件开发,基础配置直接生成,我们只需要会操作即可,操作一些API函数,注意事项就是:头文件、二值信号量一开始就有、定时器需要打开并且配置周期
1-LED-EXTI
上下拉模式和触发模式不要选择错误
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == WK_UP_Pin)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
}
}
除了第一次点open之外,其余的情况点close,不然会卡,我也不知道为什么
软件定时器
优先级、堆栈大小,定时器指令队列长度
默认MX软件生成的定时器是没有打开的,并且并没有设置周期,因此你需要做两个操作,设置周期、打开定时器 。但是做完这些操作后,发现还是有错误,原来是头文件没有加入
#include "timers.h"
xTimerChangePeriod(MyTimer0Handle,pdMS_TO_TICKS(1000),portMAX_DELAY);
xTimerStart(MyTimer0Handle,portMAX_DELAY);
MyTimer0Handle---为定时器句柄
portMAX_DELAY-为阻塞时间,因为定时器的实质是使用队列完成,因此队列的接收数据和发送数据是存在阻塞时间的
在HAL库中实现printf
#include "stdio.h" //重定义fputc函数 int fputc(int ch, FILE *f) { while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 USART1->DR = (uint8_t) ch; return ch; }
重点--记得自己添加头文件
队列实现
没有套路(记得加头文件),直接配置好,其余的我们只需要使用接收或者发送函数即可
if(KeyPress)
{
KeyPress = 0;
if(KeyNum == KEY0_PRESS)
{
//装队列数据
xQueueSend(myQueue01Handle,( void * )&senddata,0);
printf("KEY0_PRESS\r\n");
//
}
if(KeyNum == KEY1_PRESS)
{
printf("KEY1_PRESS\r\n");
//取队列数据,并且对比,对比成功,led灯反转
xQueueReceive(myQueue01Handle,( void * )&recvdata,0);
if(recvdata == 9)
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
}
if(KeyNum == WK_UP_PRESS)
{
printf("WK_UP_PRESS\r\n");
}
}
二值信号量实现
一开始创建的信号量本来没有,需要一开始就释放的,但是在我实验的过程中,我一开始就获取二值信号量,获取成功了
if(KeyNum == KEY0_PRESS)
xSemaphoreGive(myBinarySem01Handle);
if(KeyNum == KEY1_PRESS)
if( xSemaphoreTake( myBinarySem01Handle, ( TickType_t ) 0 ) == pdTRUE )
//获取成功
printf("get suceess\r\n");
else
printf("get fail\r\n");
if(KeyNum == WK_UP_PRESS)
if( xSemaphoreTake( myBinarySem01Handle, ( TickType_t ) 0 ) == pdTRUE )
//获取成功
printf("get suceess2\r\n");
else
printf("get fail2\r\n");
实验现象--按KEY1成功获取,再按一次WK,获取失败,再按KEY0释放,再按WK获取成功
计数信号量实现
定义好计数资源,直接使用函数即可
DMA实现
DMA能实现循环接收,因此在外设到存储器的时候(相当于ADC数据通过DMA传输到我们自己定义的数组中或者存储器中),我们一般希望的都是连续接收,并且这里定义了两个DMA,一个收,一个发
都是存储器到外设,我们一般是常规模式,不然会一直发送,我们这里举例了数组--串口,如果循环的话,会一直发送,陷入死循环,因此这里的memory--外设是常规模式
外设(除了内核之外的东西都是外设),除了systick、NVIC、DMA其余基本都是外设
外设到寄存器,指的就是串口或者ADC等外设的数据到我们自己定义的数组中或者存储芯片中
寄存器到外设,一般都是数组到串口然后打印出来,常用于串口
unsigned char s_buf[]="hello world\r\n";
HAL_UART_Transmit_DMA(&huart1,s_buf,sizeof(s_buf));
直接使用函数进行发送,但是一般发送需要延时一会,因为有时候被其他程序占了,使用串口发送需要稍微延时一会
此处一定要有延时,否则需要加入判断DMA是否传输完成的标志!!!
unsigned char s_buf[]="hello world 7676775645543546789876545\r\n";
HAL_UART_Transmit_DMA(&huart1,s_buf,sizeof(s_buf));
while( hdma_usart1_tx.State == HAL_DMA_STATE_READY ); //获取DMA的状态,判断它是否准备好下一次,其实就是上一次有没有完成
所以上面的可以封装一下,发送内容、发送的DMA、需要发送的串口
ADC配置
RTC配置
配置RTC时钟32.768KHZ
看门狗
在由单片机构成的微型计算机系统中单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环;或者因为用户配置代码出现BUG,导致芯片无法正常工作,出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog)简单说:看门狗的本质就是定时计数器,计数器使能之后一直在累加 而喂狗就是重新写入计数器的值,时计数器重新累加,
如果在一定时间内没有接收到喂狗信号(表示MCU已经挂了),便实现处理器的自动复位重启(发送复位信号)
喂狗是自己喂的,比如设置时间为50ms,那么你必须设置一个定时器,定时在50ms之前喂狗,不然系统会重启
clock prescaler是分频系数,下面的reload value是重载值
Tout=((4×2^prescaler) ×rlr) /32
Tout=((4×2^PRER) ×RLR)/LSI时钟频率
其中 Tout 为看门狗溢出时间(单位为 ms);prer 为看门狗时钟预分频值(IWDG_PR 值),范围为 0~7;rlr 为看门狗的重装载值(IWDG_RLR 的值);
4×2^prer直接为IWDG counter clock prescaler的值
窗口看门狗
定时时间为(4096*prescaler*(window-64+1))/32M
最小值为65,最大值为127
prescaler = 2^wdgtb
wdgtb为2的时候的最小超时值--4096*2^2*(64-64+1)/36M=
在T和W之间喂狗的话,会产生复位,或者在规定的W-0X40没有喂狗就会复位