完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
已经有快半年没有整过32单片机,为了准备电赛最近又复习了一下单片机相关的知识。发现只是看教程、手册没有啥的也不知道自己有没有学会,于是决定做一个小小的测试。测试内容是通过PWM产生频率为20HZ的占空比为50%方波,并且通过单片机测量该方波的频率。啥话不说上图看成果: 单片机产生频率为20HZ的占空比为50%方波 通过单片机产生方波很容易,设置寄存器ARR的值就能确定周期。设置CCRx的值就能设置设置占空比。 当CNT寄存值小于CCRx的值时输出低电平,大于CCRx的值时输出高电平,到达ARR的值时溢出。知道基本的原理后通过寄存器初始化和使能相关的寄存器就可以了。 这次实验采用TIM3 CH2不重映像,同时设置PWM模式为向上计数模式。配置步骤如下:
//PWM输出初始化 //arr:自动重装值 //psc:时钟预分频数 void TIM3_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //①使能 GPIO 和 AFIO 复用功能时钟 // GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PC7 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //TIM_CH2 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA //初始化TIM3 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 //初始化TIM3 Channel2 PWM模式 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高 TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2 TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的预装载寄存器 TIM_Cmd(TIM3, ENABLE); //使能TIM3 } 以上代码就完成了PWM的初始化,如果要产生20HZ的波形,那么就相当于要没50ms要溢出一次,那么我们可以设置arr的值为499,psc的值为7199。Tout= ((arr+1)*(psc+1))/Tclk=(499+1)* ( 7199+1)/72=50ms 。说明计数到500次为50ms,那么设置CCR2的值为250就可以实现占空比为50%。 单片机测量频率并显示 测量频率的思路有很多种,网上有关于ADC测量电压,也有关于输入捕获的。但是上次电赛校赛,学长用的是外部中断结合定时器中断来实现的,思路也比较简单。就是下降沿触发外部中断,然后打开定时器计数。当再次进入外部中断时停止计数清楚相关的标志位。这样就得到了一个计数次数,通过计数次数就可以计算出电平经历变化用的时间,时间的倒数就是相关的频率。本次实验用的是外部中断三(EXTI3)对应PE3口。 void EXTIX_Init(void) { EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; KEY_Init(); // 按键端口初始化 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟 //GPIOE.3 中断线以及中断初始化配置 下降沿触发 //KEY1 GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3); EXTI_InitStructure.EXTI_Line=EXTI_Line3; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器 NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //使能按键KEY1所在的外部中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级1 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道 NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 } void EXTI3_IRQHandler(void) { if(half_cricle == 0) { TIM2->CNT = 0; TIM_Cmd(TIM2, ENABLE); //使能TIMx half_cricle = 1; } else if(half_cricle == 1) { time_of_circle = TIM2->CNT; TIM2->CNT = 0; TIM_Cmd(TIM2, ENABLE); //使能TIMx } EXTI_ClearITPendingBit(EXTI_Line3); } 定时器2初始化: void TIM2_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 // TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断 // NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断 // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级 // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级 // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 // NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 } 主函数: int main(void) { char str[10]; delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 LED_Init(); //初始化与LED连接的硬件接口 EXTIX_Init(); //初始化外部中断输入 LCD_Init(); TIM3_PWM_Init(499,7199); TIM2_Init(4999,7199); LED0=0; //先点亮红灯 TIM_SetCompare2(TIM3,250);//设置CCR2的寄存器值为250占空比为50% LCD_ShowString(45,125,200,30,16,"-----freqency-----"); LCD_ShowString(130,165,32,30,16,"HZ"); while(1) { freq=10000.0 / (float)time_of_circle; sprintf(str,"%.2f",freq); LCD_ShowString(50,165,64,30,16,str); LCD_ShowString(45,125,200,30,16,"-----freqency-----"); LCD_ShowString(130,165,32,30,16,"HZ"); } } 以上就是几个主要的函数,用库函数配置比寄存器配置舒服多了,之前一直整寄存器版本的,现在接触库函数觉得实在是太方便啦! |
|
|
|
只有小组成员才能发言,加入小组>>
2563 浏览 0 评论
762浏览 1评论
520浏览 0评论
273浏览 0评论
454浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-29 01:13 , Processed in 1.257052 second(s), Total 78, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号