TIM2+DMA配置
void TIM2_Cap_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure;//初始化GPIO结构体 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//初始化计时器结构体 NVIC_InitTypeDef NVIC_InitStructure;//中断配置结构体 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //TIM2时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //GPIOA时钟使能 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0输入 GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0清除之前配置 TIM_TimeBaseStructure.TIM_Period = arr; //预分频(时钟分频) 比如:72M/(arr+1)=24M TIM_TimeBaseStructure.TIM_Prescaler =psc; //计数值TIMx->CNT达到psc后会触发中断 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟不分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;//是重复计数,就是重复溢出多少次才给你来一个溢出中断, TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择通道1 TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿触发 TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI上 TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //输入不分频 TIM2_ICInitStructure.TIM_ICFilter = 0x00;//不滤波 TIM_ICInit(TIM2, &TIM2_ICInitStructure); NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE); TIM_ARRPreloadConfig(TIM2,ENABLE); TIM_DMACmd(TIM2,TIM_DMA_Update, ENABLE); TIM_DMACmd(TIM2,TIM_DMA_CC1, ENABLE); TIM_Cmd(TIM2,ENABLE); }
https://blog.csdn.net/Britripe/article/details/83865599
void TIM2_IRQHandler(void) { TIM2->CNT=0;//清楚CNT寄存器 TIM2->SR=0; }
void TIMDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr) { RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//打开DMA1时钟 DMA_DeInit(DMA_CHx); DMA1_MEM_LEN=cndtr; DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;//外设地址 DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //传输方向外设到内存 DMA_InitStructure.DMA_BufferSize = cndtr; //传输数量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不自增 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据大小为半字节 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //内存数据大小为半字节 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//重复 DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高优先级 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA_CHx, &DMA_InitStructure); }
#define Lenth 12 u32 res=0; u16 buffer[Lenth]; int main(void) { u32 sec; int i=0; NVIC_Configuration(); delay_init(); uart_init(115200); MYDMA_Config(DMA1_Channel5,(u32)&TIM2->CCR1,(u32)buffer,12);//传输方向TIM2->CCR1到buffer DMA_Cmd(DMA1_Channel5,ENABLE);//打开DMA通道15 TIM2_Cap_Init(65535,0); printf("配置完成\n"); while(1) { while(DMA_GetFlagStatus(DMA1_FLAG_TC5)==RESET);//等待DMA1通过5接收完成 DMA_ClearFlag(DMA1_FLAG_TC5); TIM_Cmd(TIM5,DISABLE); for(i=0;i<12;i++)//数据量为12个加起来求平均 { res+=buffer[i]; buffer[i]=0; } printf("counts:%d\r\n",72000000/((res/12)+25));//转换为频率 res=0; DMA_Cmd(DMA1_Channel5,ENABLE); TIM_Cmd(TIM5,ENABLE); } }
测试后中断中占用25个时钟周期 所以在计算加上去
该程序会将计算出的频率值通过串口发送至电脑,在1K到200K范围内达到千分之一精度
https://blog.csdn.net/shu_8708/article/details/73481305
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决