网站建设客户资料收集清单,招考网站开发,京津冀协同发展战略,oss挂载到wordpress1.定时器概念和作用
在编程任务中#xff0c;定时器是非常常用的一个问题。当需要定时发送数据#xff0c;定时起某个任务#xff0c;定时做某个操作等等#xff0c;这些都离不开定时器。本文基于以STM32F4xx系列开发板#xff0c;介绍一下基本定时器。
2.基本定时器TIM…1.定时器概念和作用
在编程任务中定时器是非常常用的一个问题。当需要定时发送数据定时起某个任务定时做某个操作等等这些都离不开定时器。本文基于以STM32F4xx系列开发板介绍一下基本定时器。
2.基本定时器TIM6和TIM7介绍
如下图所示基本定时器有两个分别是TIM6和TIM7。它们的计数器都是16位的也就是意味着取值范围对无符号数来说是0到65535。基本定时器工作时主要涉及三个寄存器分别是计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR)。 顾名思义计数器寄存器(TIMx_CNT)是用来计数的它的值是从0开始递增。而当计数寄存器的值等于自动重载寄存器(TIMx_ARR)中的值时就会生 成事件将相关事件标志位置位生成中断输出。
预分频器寄存器(TIMx_PSC)是用来分频的它有一个输入时钟CK_PSC和一个输出时钟CK_CNT。 CK_CNTfCK_PSC/(PSC[15:0]1)
定时周期就是由预分频器寄存器(TIMx_PSC)和自动重载寄存器(TIMx_ARR)来决定。
假如自动重载寄存器(TIMx_ARR)的值为4999即计数器寄存器(TIMx_CNT)从0开始计数到4999时总共计数50000次就会产生中断。假如此时定时器的定时频率为10000Hz那么一个定时周期就是50000*1/10000 5S。即5S就会产生一次定时中断我们就可以在中断处理程序中添加我们的业务逻辑代码。
3.代码
/*** brief 初始化基本定时器* param 无* retval 无*/
void TIMx_Configuration(TIM_TypeDef * tim)
{TIMx_NVIC_Configuration(tim); TIM_Mode_Config(tim);
}/*** brief 基本定时器 TIMx,x[6,7]中断优先级配置* param TIM_TypeDef * timTIM6 or TIM7* retval 无*/
static void TIMx_NVIC_Configuration(TIM_TypeDef * tim)
{if (tim TIM6){NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断来源NVIC_InitStructure.NVIC_IRQChannel BASIC_TIM_IRQn; // 设置抢占优先级NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0; // 设置子优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority 3; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStructure);}if (tim TIM7){NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断来源NVIC_InitStructure.NVIC_IRQChannel BASIC_TIM7_IRQn; // 设置抢占优先级NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0; // 设置子优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority 3; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStructure);}
}/** 注意TIM_TimeBaseInitTypeDef结构体中有5个成员TIM6和TIM7的寄存器里面只有* TIM_Prescaler和TIM_Period所以使用TIM6和TIM7的时候只需初始化这两个成员即可* 另外三个成员是通用定时器和高级定时器才有.*-----------------------------------------------------------------------------* TIM_Prescaler 都有* TIM_CounterMode TIMx,x[6,7]没有其他都有基本定时器* TIM_Period 都有* TIM_ClockDivision TIMx,x[6,7]没有其他都有基本定时器* TIM_RepetitionCounter TIMx,x[1,8]才有高级定时器*-----------------------------------------------------------------------------*/
static void TIM_Mode_Config(TIM_TypeDef * tim)
{if (tim TIM6){TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 开启TIMx_CLK,x[6,7] RCC_APB1PeriphClockCmd(BASIC_TIM_CLK, ENABLE); /* 累计 TIM_Period个后产生一个更新或中断*/ //当定时器从0计数到4999即为5000次为一个定时周期TIM_TimeBaseStructure.TIM_Period 60 - 1; // 每0.34ms启动一个定时器中断//定时时钟源 TIMxCLK 2 * PCLK1 // PCLK1 HCLK / 4 // TIMxCLKHCLK/2SystemCoreClock/284MHz// 设定 定时器频率为 TIMxCLK/(TIM_Prescaler1)10000HzTIM_TimeBaseStructure.TIM_Prescaler 1000 - 1; // 初始化定时器 TIMx, x[2,3,4,5]TIM_TimeBaseInit(BASIC_TIM, TIM_TimeBaseStructure);// 清除定时器更新中断标志TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);// 开启定时器更新中断TIM_ITConfig(BASIC_TIM,TIM_IT_Update,ENABLE);// 使能定时器// TIM_Cmd(BASIC_TIM, ENABLE); }if (tim TIM7){TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 开启TIMx_CLK,x[6,7] RCC_APB1PeriphClockCmd(BASIC_TIM7_CLK, ENABLE); /* 累计 TIM_Period个后产生一个更新或中断*/ //当定时器从0计数到167即为168次为一个定时周期TIM_TimeBaseStructure.TIM_Period 50000 - 1; // 5s//定时时钟源 TIMxCLK 2 * PCLK1 // PCLK1 HCLK / 4 // TIMxCLKHCLK/2SystemCoreClock/284MHz// 设定 定时器频率为 TIMxCLK/(TIM_Prescaler1)10000HzTIM_TimeBaseStructure.TIM_Prescaler 8400 - 1; //定时器频率10 Khz// 初始化定时器 TIMx, x[2,3,4,5]TIM_TimeBaseInit(BASIC_TIM7, TIM_TimeBaseStructure);// 清除定时器更新中断标志TIM_ClearFlag(BASIC_TIM7, TIM_FLAG_Update);// 开启定时器更新中断TIM_ITConfig(BASIC_TIM7,TIM_IT_Update,ENABLE);// 使能定时器// TIM_Cmd(BASIC_TIM, ENABLE); }
}当产生中断时中断号和中断处理函数为 中断号
实现业务逻辑为当RS232串口接收到第一个字节数据时把TIM7给使能使能后开始计数。当一个定时周期本程序设置的是5s,认为RS232串口已经收好一串数据了此时在定时中断处理承租中把一个全局变量标志置上置成1认为数据接收完成可以进入数据处理了在main函数中添加对数据的处理的业务逻辑代码。 //串口中断处理函数---接收
#define UART_BUFF_SIZE 1024
volatile uint16_t uart_len 0;
uint8_t g_uart_buff[UART_BUFF_SIZE] {0};extern uint8_t g_recvData;void USART6_IRQHandler(void) //当串口上有字节传送过来的时候,便会产生中断,即每个字节过来会产生一次串口接收中断
{uint8_t clear;if(uart_lenUART_BUFF_SIZE){while(USART_GetITStatus(USART6, USART_IT_RXNE) ! RESET) // USART6串口的接收数据寄存器非空,表明有新的数据待读取{g_uart_buff[uart_len] USART_ReceiveData(USART6);uart_len;TIM_Cmd(BASIC_TIM7, ENABLE); //当转接板接收到长强板第一个数时就把Tim7的使能给置上Tim7开始计数USART_ClearITPendingBit(USART6, USART_IT_RXNE);}}else{ // 接收的数据长度超过UART_BUFF_SIZE 时这次数据全部丢弃USART_ClearITPendingBit(USART6, USART_IT_RXNE);clean_usart_rebuff(); }if (USART_GetITStatus(USART6, USART_IT_IDLE) ! RESET) // 用来判断是否收到一帧数据 https://blog.csdn.net/ASKLW/article/details/79246786{ //数据通过RS232接收到后进入逻辑处理调用motor.c相关函数// 定义一个全局变量当数据接收完成后把全局变量置为true,后续进行处理clear USART6-SR; //先读SR,再读DR才能完成idle中断的清零否则一直进入中断。clear USART6-DR;uint16_t len 0;
// char str[1024] {0};
// sprintf(str, %d, ii);
// Usart_SendByte(USART6, len);
// ii;
//Usart_SendString(USART6, get_usart_rebuff(len));
//Usart_SendString(USART6, AABBCCDDEEFFGG); // uint16_t len1 0;
// const char* cmdline get_usart_rebuff(len1); // 测试用例0x81VT100
// printf(cmdlineusart %s\n, cmdline);
//Usart_SendString(USART6, 0x82VT100); g_recvData 0x01;}
}
中断处理程序
extern uint8_t g_timer7;
void BASIC_TIM7_IRQHandler (void)
{if ( TIM_GetITStatus( BASIC_TIM7, TIM_IT_Update) ! RESET ) {
// printf(timer);g_timer7 1; //在定时器中断。把标志位置上TIM_ClearITPendingBit(BASIC_TIM7 , TIM_IT_Update); }
}数据处理 if (g_timer7 0x01) //表明接收数据已经完成需要进入对数据的处理 g_recvData 0x01{g_timer7 0; uint16_t len 0;const char* cmdline get_usart_rebuff(len); // 测试用例0x81VT100printf(cmdline%s\n, cmdline);
// Usart_SendString(USART6, get_usart_rebuff(len)); } 交流碰撞思想火花欢迎大家留言评论