59人参与 • 2024-08-06 • stm32
◼ 总通道数:4;
◼ 计数器宽度:16位;
◼ 时钟源可选:内部时钟,内部触发,外部输入,外部触发;
◼ 多种计数模式:向上计数,向下计数和中央计数;
◼ 正交编码器接口:被用来追踪运动和分辨旋转方向和位置;
◼ 霍尔传感器接口:用来做三相电机控制;
◼ 可编程的预分频器:16位,运行时可以被改变;
◼ 每个通道可配置:输入捕获模式,输出比较模式,可编程的pwm模式,单脉冲模式;
◼ 可编程的死区时间;
◼ 自动重装载功能;
◼ 可编程的计数器重复功能;
◼ 中止输入功能;
◼ 中断输出和dma请求:更新事件,触发事件,比较/捕获事件,换相事件和中止事件;
◼ 多个定时器的菊链使得一个定时器可以同时启动多个定时器;
◼ 定时器的同步允许被选择的定时器在同一个时钟周期开始计数;
◼ 定时器主-从管理。
高级定时器timer0是挂在apb2上的,最大频率120mhz,这里使用120mhz。
时钟使能,令rcu_apb2en的11位bit为1即可。
需要配置的寄存器为上面框出来的。
/*
* dasen - 2023/4/28
* pwm.c - 产生三组互补pwm波
*/
#include "pwm.h"
void pwm_gpioinit(void)
{
//pa8(复用) - ch0 | pb13(复用) - ch0-n
//pa9(复用) - ch1 | pb14(复用) - ch1-n
//pa10(复用) - ch2 | pb15(复用) - ch2-n
rcu_apb2en |=(1<<2);//gpioa时钟使能
rcu_apb2en |=(1<<3);//gpiob时钟使能
rcu_apb2en |=(1<<0);//复用io时钟使能
//pa8
gpio_ctl1(gpioa) &=~(0x0f<<0);//清除ctl配置
gpio_ctl1(gpioa) |=(3<<0);//输出模式,最大速度50mhz
gpio_ctl1(gpioa) |=(2<<2);//afio推挽输出
//pa9
gpio_ctl1(gpioa) &=~(0x0f<<4);//清除ctl配置
gpio_ctl1(gpioa) |=(3<<4);//输出模式,最大速度50mhz
gpio_ctl1(gpioa) |=(2<<6);//afio推挽输出
//pa10
gpio_ctl1(gpioa) &=~(0x0f<<8);//清除ctl配置
gpio_ctl1(gpioa) |=(3<<8);//输出模式,最大速度50mhz
gpio_ctl1(gpioa) |=(2<<10);//afio推挽输出
//pb13
gpio_ctl1(gpiob) &=~(0x0f<<20);//清除ctl配置
gpio_ctl1(gpiob) |=(3<<20);//输出模式,最大速度50mhz
gpio_ctl1(gpiob) |=(2<<22);//afio推挽输出
//pb14
gpio_ctl1(gpiob) &=~(0x0f<<24);//清除ctl配置
gpio_ctl1(gpiob) |=(3<<24);//输出模式,最大速度50mhz
gpio_ctl1(gpiob) |=(2<<26);//afio推挽输出
//pb15
gpio_ctl1(gpiob) &=~(0x0f<<28);//清除ctl配置
gpio_ctl1(gpiob) |=(3<<28);//输出模式,最大速度50mhz
gpio_ctl1(gpiob) |=(2<<30);//afio推挽输出
afio_pcf0 &=~(3<<6);
afio_pcf0 |=(0<<6);//没有重映射
}
void timer0_initpwm(uint16_t prescale, uint16_t period)
{
rcu_apb2en |=(1<<11);//timer0时钟使能
pwm_gpioinit();//gpio config
timer_ctl0(timer0) = 0;//清除控制寄存器0配置
timer_ctl0(timer0) |=(0<<8);//通过软件配置ckdiv,规定定时器时钟(ck_timer) 与死区时间和数字滤波器采样时钟(dts)之间的分频系数。:
//00:fdts=fck_timer;
//01:fdts= fck_timer /2;
//10:fdts= fck_timer /4;
//11:保留
timer_ctl0(timer0) |=(1<<7);//1:使能timerx_car寄存器的影子寄存器(自动重载影子使能)
timer_ctl0(timer0) |=(0<<5);//计数器对齐模式选择:00:无中央对齐计数模式(边沿对齐模式)。 dir位指定了计数方向。其他值为中央对齐模式
timer_ctl0(timer0) |=(0<<4);//0:向上计数;1:向下计数
timer_ctl0(timer0) |=(1<<2);//选择更新事件源。1:下列事件会产生更新中断或dma请求:计数器溢出/下溢
timer_ctl0(timer0) |=(0<<1);//该位用来使能或禁能更新事件的产生。0:更新事件使能.1:更新事件禁能.
timer_ctl1(timer0)=0;//清除控制寄存器1配置
timer_ctl1(timer0) |=(1<<3);//dma请求源选择:0:当通道捕获/比较事件发生时,发送通道x的dma请求 .1:当更新事件发生,发送通道x的dma请求
timer_ctl1(timer0) |=(0<<2);//换相控制影子寄存器更新控制:当换相控制影子寄存器(chxen, chxnen和chxcomctl位)使能(ccse=1),这些影子寄存器更新控制如下:(当通道没有互补输出时,此位无效。)
//0:cmtg位被置1时更新影子寄存器
//1:当cmtg位被置1或检测到trigi上升沿时,影子寄存器更新
timer_ctl1(timer0) |=(1<<0);//换相控制影子使能:0:影子寄存器chxen, chxnen和chxcomctl位禁能.
//1:影子寄存器chxen, chxnen和chxcomctl位使能.
//如果这些位已经被写入了,换相事件到来时这些位才被更新
//当通道没有互补输出时,此位无效
timer_smcfg(timer0) =0;//清除从模式配置寄存器配置
timer_dmainten(timer0) =0;//清除dma和中断使能寄存器
timer_dmainten(timer0) |=(0<<0);//0:禁止更新中断;1:使能更新中断
timer_intf(timer0) =0;//中断标志位清零 【timer_intf(timer0)&(1<<0) 为upif更新中断标志位:1:发生更新中断;0:无更新中断发生。】
timer_swevg(timer0) =0;//软件事件产生寄存器清零
/******************************pwm通道配置 start*********************************/
//先把chctl2的chxen清零,才配置chctl0
timer_chctl2(timer0) =0;//通道控制寄存器2清零
timer_chctl0(timer0) =0;//通道控制寄存器0清零
timer_chctl1(timer0) =0;//通道控制寄存器1清零
//ch0
timer_chctl0(timer0) |=(0<<0);//通道0 i/o模式选择:00:通道0配置为输出
timer_chctl0(timer0) |=(1<<3);//1:使能通道0输出/比较影子寄存器
timer_chctl0(timer0) |=(6<<4);//110:pwm 模式0。在向上计数时,一旦计数器值小于timerx_ch0cv时,o0cpre为高电平,否则为低电平。在向下计数时,一旦计数器的值大于timerx_ch0cv时,o0cpre 为低电平,否则为高电平。
//ch1
timer_chctl0(timer0) |=(0<<8);
timer_chctl0(timer0) |=(1<<11);
timer_chctl0(timer0) |=(6<<12);
//ch2
timer_chctl1(timer0) |=(0<<0);
timer_chctl1(timer0) |=(1<<3);
timer_chctl1(timer0) |=(6<<4);
//ch0 en
timer_chctl2(timer0) |=(1<<0);//1:使能通道x
timer_chctl2(timer0) |=(0<<1);//通道x极性:0:通道x高电平为有效电平;1:通道x低电平为有效电平
//ch0-n en
timer_chctl2(timer0) |=(1<<2);//1:使能通道x互补输出
timer_chctl2(timer0) |=(0<<3);//通道x互补输出极性:0:通道x互补输出高电平为有效电平;1:通道x互补输出低电平为有效电平
//ch1 en
timer_chctl2(timer0) |=(1<<4);//1:使能通道x
timer_chctl2(timer0) |=(0<<5);//通道x极性:0:通道x高电平为有效电平;1:通道x低电平为有效电平
//ch1-n en
timer_chctl2(timer0) |=(1<<6);//1:使能通道x互补输出
timer_chctl2(timer0) |=(0<<7);//通道x互补输出极性:0:通道x互补输出高电平为有效电平;1:通道x互补输出低电平为有效电平
//ch2 en
timer_chctl2(timer0) |=(1<<8);//1:使能通道x
timer_chctl2(timer0) |=(0<<9);//通道x极性:0:通道x高电平为有效电平;1:通道x低电平为有效电平
//ch2-n en
timer_chctl2(timer0) |=(1<<10);//1:使能通道x互补输出
timer_chctl2(timer0) |=(0<<11);//通道x互补输出极性:0:通道x互补输出高电平为有效电平;1:通道x互补输出低电平为有效电平
timer_swevg(timer0) |=(1<<5);//通道换相更新事件发生:1:产生通道控制更新事件。此位由软件置1,由硬件自动清0. 当此位被置1,通道捕获/比较控制寄存器 (chxen, chxnen 和chxcomctl) 的互补输出被更新。
/******************************pwm通道配置 end*********************************/
//时基配置
timer_cnt(timer0)=0;//计数器寄存器清零
timer_psc(timer0) =prescale;//tim_clk=120mhz/(prescale+1)。计数器时钟等于timer_ck时钟除以(psc+1),每次当更新事件产生时,psc 的值被装入到对应的影子寄存器。
timer_car(timer0) =period;//计数器自动重载值
timer_crep(timer0) = 5;//重复计数器的值;这些位定义了更新事件的产生速率。重复计数器计数值减为0时产生更新事件。影子寄存器的更新速率也会受这些位影响(前提是影子寄存器被使能)。
//比较寄存器配置
timer_ch0cv(timer0) = period>>1;//当通道0配置为输出模式时,这些位包含了即将和计数器比较的值。使能相应影子寄存器后,影子寄存器值随每次更新事件更新。
timer_ch1cv(timer0) = period>>1;
timer_ch2cv(timer0) = period>>1;
timer_cchp(timer0) &=~(3<<8);//00:禁能保护模式。无写保护.
timer_cchp(timer0) =0;//互补通道保护寄存器清零
timer_cchp(timer0) |=(1<<15);//所有的通道输出使能
timer_cchp(timer0) |=(0<<14);//自动输出使能:0:poen位只能使用软件方式置1;1:如果中止输入无效,下一次更新事件发生时,poen位将会置1
//此位只有在timerx_cchp寄存器的prot [1:0] =00时才可修改。
timer_cchp(timer0) |=(1<<11);//0:当poen位被置1,通道输出信号 (chx_o/ chx_on)被禁止;1:当poen位被置1,通道输出信号 (chx_o / chx_on)被使能,和timer0_chctl2寄存器chxen/chxnen位有关
//此位在timerx_cchp寄存器的prot [1:0]=10或11时不能被更改。
timer_cchp(timer0) |=(0<<10);//0:当poen位被清0,通道输出信号 (chx_o/ chx_on)被禁止;1:当poen位被清0,通道输出信号 (chx_o / chx_on)被使能,和timer0_chctl2寄存器chxen/chxnen位有关
//此位在timerx_cchp寄存器的prot [1:0]=10或11时不能被更改。
//死区时间
timer_cchp(timer0) |=(96<<0);//delay >= 8.33ns*96=799.68ns
timer_cfg(timer0)=0;
timer_cfg(timer0)|=1;//1:如果poen位与ios位均为0,则输出无效
timer_swevg(timer0) |=(1<<0);//更新事件产生:1:产生更新事件。此位由软件置1,被硬件自动清0。当此位被置1,如果选择了中央对齐或向上计数模式,计数器被清0。否则(向下计数模式)计数器将载入自动重载值,预分频计数器将同时被清除。
timer_ctl0(timer0) |=(1<<0);//计数器使能:0:计数器禁能;1:计数器使能
}
/*
ck_sys is 120000000
ck_ahb is 120000000
ck_apb1 is 60000000
ck_apb2 is 120000000
ck_sys is 120000000
ck_ahb is 120000000
ck_apb1 is 60000000
ck_apb2 is 120000000
*/
#include "gd32f30x.h"
#include <stdio.h>
#include "main.h"
#include "pwm.h"
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
timer0_initpwm(0,4000-1);//120mhz/4000=30khz
while (1);
}
接示波器观察,可以看到三组互补pwm波形,占空比为50%,频率30khz。
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论