AT32定时器

一、定时器中断

定时器溢出中断是定时器最基础功能,进入中断的时间周期可由相关寄存器配置。
1、定时器计数器值 TMRx_CVAL
2、 定时器预分频寄存器 TMRx_DIV
3、定时器周期寄存器(TMRx_PR)
定时器中断频率计算公式如下:
 

配置流程

编写定时器溢出中断函数的应用程序
开启定时器外设时钟
配置定时器 TMRx_DIV 寄存器和 TMRx_PR 寄存器
配置定时器为向上计数方向
5 开启定时器溢出中断
开启 NVIC 溢出中断
7 开启定时器计数

代码介绍

main函数

int main(void)
{
/* 系统时钟配置 */
system_clock_config();
/* LED 延时函数等初始化 */
at32_board_init();
/* 获取系统时钟 */
crm_clocks_freq_get(&crm_clocks_freq_struct);
/* 点亮 LED2/LED3/LED4 */
at32_led_on(LED2);
at32_led_on(LED3);
at32_led_on(LED4);
/* 开启 TMR1 时钟 */
crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);
/* 配置定时器 TMRx_DIV 寄存器和 TMRx_PR 寄存器 */
/* systemclock/24000/10000 = 1hz */
tmr_base_init(TMR1, 9999, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
/*配置定时器为向上计数方向,如果选择向上计数也可以不配置该语句,
因为 TMR 默认就是向上计数模式 */
tmr_cnt_dir_set(TMR1, TMR_COUNT_UP);
/* 开启定时器溢出中断 */
tmr_interrupt_enable(TMR1, TMR_OVF_INT, TRUE);
/* 开启 NVIC 溢出中断 */
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 0, 0);
/* 开启定时器计数 */
tmr_counter_enable(TMR1, TRUE);
clkout_config();
while(1)
{

}
}

中断函数

void TMR1_OVF_TMR10_IRQHandler(void)
{
 /* 判断溢出标志位是否置起 */
 if(tmr_flag_get(TMR1, TMR_OVF_FLAG) == SET)
 {
 /* 增加应用程序 */
 at32_led_toggle(LED3);
 tmr_flag_clear(TMR1, TMR_OVF_FLAG);
 }
}

实验效果

LED3 1 秒翻转一次

二、PWM输出

PWM 输出是定时器最常用的输出模式,分为 PWM 模式 A PWM 模式 B。其差异在于:
PWM 模式 A
OWCDIR=0,若 TMRx_C1DT>TMRx_CVAL 时设置 C1ORAW 为高,否则为低;
OWCDIR=1,若 TMRx_ C1DT <TMRx_CVAL 时设置 C1ORAW 为低,否则为高。
PWM 模式 B
OWCDIR=0,若 TMRx_ C1DT >TMRx_CVAL 时设置 C1ORAW 为低,否则为高;
OWCDIR=1,若 TMRx_ C1DT <TMRx_CVAL 时设置 C1ORAW 为高,否则为低。

配置流程

1、 开启定时器外设时钟
2、 配置输出管脚
3、 配置定时器 TMRx_DIV 寄存器和 TMRx_PR 寄存器
4、 配置定时器为向上计数方向
5、 配置定时器输出通道为 PWM 模式 B
6、 开启定时器计数

代码介绍

int main(void)
{
 system_clock_config();
 /* 初始化板载设备 */
 at32_board_init();
 
 /* get system clock */
 crm_clocks_freq_get(&crm_clocks_freq_struct);
 /* turn led2/led3/led4 on */
 at32_led_on(LED2);
 at32_led_on(LED3);
 at32_led_on(LED4);
 /* 打开 tmr1/gpioa/gpiob 时钟 */
 crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);
 crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
 crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
 /* 配置 TMR1 输出管脚 */
 gpio_init_struct.gpio_pins = GPIO_PINS_8 | GPIO_PINS_9 | GPIO_PINS_10 | GPIO_PINS_11;
 gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
 gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
 gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
 gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
 gpio_init(GPIOA, &gpio_init_struct);
gpio_init_struct.gpio_pins = GPIO_PINS_13 | GPIO_PINS_14 | GPIO_PINS_15;
 gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
 gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
 gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
 gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
 gpio_init(GPIOB, &gpio_init_struct);
 gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE8, GPIO_MUX_1);
 gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE9, GPIO_MUX_1);
 gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE10, GPIO_MUX_1);
 gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE11, GPIO_MUX_1);
 gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE13, GPIO_MUX_1);
 gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE14, GPIO_MUX_1);
 gpio_pin_mux_config(GPIOB, GPIO_PINS_SOURCE15, GPIO_MUX_1);
 /* tmr1 初始化 ---------------------------------------------------
 generate 7 pwm signals with 4 different duty cycles:
 prescaler = 0, tmr1 counter clock = apb2_freq *2
 the objective is to generate 7 pwm signal at 17.57 khz:
 - tim1_period = (apb2_freq * 2 / 17570) - 1
 the channel 1 and channel 1n duty cycle is set to 50%
 the channel 2 and channel 2n duty cycle is set to 37.5%
 the channel 3 and channel 3n duty cycle is set to 25%
 the channel 4 duty cycle is set to 12.5%
 the timer pulse is calculated as follows:
 - channelxpulse = dutycycle * (tim1_period - 1) / 100
 ----------------------------------------------------------------------- */
 /* compute the value to be set in arr regiter to generate signal frequency at 17.57 khz */
 timerperiod = ((crm_clocks_freq_struct.apb2_freq * 2) / 17570 ) - 1;
 /* compute ccr1 value to generate a duty cycle at 50% for channel 1 and 1n */
 channel1pulse = (uint16_t) (((uint32_t) 5 * (timerperiod - 1)) / 10);
 /* compute ccr2 value to generate a duty cycle at 37.5% for channel 2 and 2n */
 channel2pulse = (uint16_t) (((uint32_t) 375 * (timerperiod - 1)) / 1000);
 /* compute ccr3 value to generate a duty cycle at 25% for channel 3 and 3n */
 channel3pulse = (uint16_t) (((uint32_t) 25 * (timerperiod - 1)) / 100);
 /* compute ccr4 value to generate a duty cycle at 12.5% for channel 4 */
channel4pulse = (uint16_t) (((uint32_t) 125 * (timerperiod- 1)) / 1000);
 /* 配置 TMR 为向上计数模式 */
 tmr_base_init(TMR1, timerperiod, 0);
 tmr_cnt_dir_set(TMR1, TMR_COUNT_UP);
 /* 配置通道 1/2/3/4 */
 tmr_output_default_para_init(&tmr_output_struct);
 tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_B;
 tmr_output_struct.oc_output_state = TRUE;
 tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_LOW;
 tmr_output_struct.oc_idle_state = TRUE;
 tmr_output_struct.occ_output_state = TRUE;
 tmr_output_struct.occ_polarity = TMR_OUTPUT_ACTIVE_HIGH;
 tmr_output_struct.occ_idle_state = FALSE;
 /* channel 1 */
 tmr_output_channel_config(TMR1, TMR_SELECT_CHANNEL_1, &tmr_output_struct);
 tmr_channel_value_set(TMR1, TMR_SELECT_CHANNEL_1, channel1pulse);
 /* channel 2 */
 tmr_output_channel_config(TMR1, TMR_SELECT_CHANNEL_2, &tmr_output_struct);
 tmr_channel_value_set(TMR1, TMR_SELECT_CHANNEL_2, channel2pulse);
 /* channel 3 */
 tmr_output_channel_config(TMR1, TMR_SELECT_CHANNEL_3, &tmr_output_struct);
 tmr_channel_value_set(TMR1, TMR_SELECT_CHANNEL_3, channel3pulse);
 /* channel 4 */
 tmr_output_channel_config(TMR1, TMR_SELECT_CHANNEL_4, &tmr_output_struct);
 tmr_channel_value_set(TMR1, TMR_SELECT_CHANNEL_4, channel4pulse);
 /*TMR1 输出总开关打开 */
 tmr_output_enable(TMR1, TRUE);
 /*使能 TMR1 */
 tmr_counter_enable(TMR1, TRUE);
 while(1)
 {}

实验效果

图中通道 1 4 输出频率相同但占空比不同的波形,互补通道通过输出极性的调节与其对应的 通道输出相同的波形。
未完待续~
### AT89C51 单片机定时器设置 100ms 延时 TH0 和 TL0 的初始值计算 为了实现 100ms 的延时,需要配置 AT89C51 单片机定时器。以下是详细的计算过程: #### 1. 定时器工作模式的选择 AT89C51 单片机支持多种定时器工作模式,在这里选择 **模式 1 (16 位自动重装载)** 来实现较长的定时需求。 #### 2. 晶振频率设定 假设单片机使用的晶振频率为 11.0592 MHz,则机器周期 \( T \) 可表示为: \[ T = \frac{1}{f_{osc}} \times 12 = \frac{1}{11.0592 \times 10^6} \times 12 = 1.085 \mu s \] #### 3. 计算所需计数值 对于 100ms 的延时,所需的总脉冲数 \( N \) 为: \[ N = \text{延迟时间} / \text{机器周期} = 100 \times 10^{-3} / 1.085 \times 10^{-6} = 92174 \] 由于定时器是 16 位寄存器,最大可存储值为 \( 2^{16} - 1 = 65535 \),因此无法一次性完成如此多的计数。此时需利用初值法来间接达到目标。 #### 4. 初值计算 设定时器的初值为 \( X \),则每次溢出前实际计数值为: \[ M = 65536 - X \] 其中 \( M \) 表示一次溢出所对应的计数值。为了让多次溢出后的总计数值等于 92174,应满足以下条件: \[ kM \leq 92174 < (k+1)M \] 即找到合适的整数 \( k \) 并求解 \( X \)。 取 \( k=1 \) 进行尝试(因为一般情况下只需要一次溢出来接近目标),得到: \[ M = 92174 \Rightarrow X = 65536 - 92174 = -26638 \ (\text{超出范围})\] 显然,\( k=1 \) 不够大,继续增大 \( k \): 当 \( k=2 \) 时, \[ M = \lceil 92174 / 2 \rceil = 46087 \Rightarrow X = 65536 - 46087 = 19449 \] 验证此方案是否可行: 两次溢出后总计数值为: \[ 2 \times 46087 = 92174 \approx 100ms \] #### 5. 将初值拆分为高字节和低字节 将 \( X = 19449 \) 转化为十六进制形式: \[ X = H'4BFB' \] 将其分配到 TH0 和 TL0 寄存器中: \[ TH0 = H'4B', \quad TL0 = H'FB' \] 最终结果为: \[ TH0 = 0x4B, \quad TL0 = 0xFB \][^1] --- ### C语言代码实现 下面是用于初始化定时器并启动 100ms 延时的功能代码片段: ```c #include <reg51.h> void Timer_Init() { TMOD = 0x01; // 设置定时器 T0 工作于模式 1 TH0 = 0x4B; // 高字节加载初值 TL0 = 0xFB; // 低字节加载初值 TR0 = 1; // 启动定时器 T0 } unsigned char flag; void main() { EA = 1; // 开启全局中断 ET0 = 1; // 开启定时器 T0 中断 Timer_Init(); // 初始化定时器 while(1){ if(flag){ // 如果标志位置 1,说明已发生过一次中断 flag = 0; // 执行其他任务... } } } // 定义定时器 T0 的中断服务程序 void Timer_ISR(void) interrupt 1 { TH0 = 0x4B; // 重新加载初值 TL0 = 0xFB; // 重新加载初值 flag = 1; // 标志位通知主循环已完成一次 100ms 延时 } ``` --- ### 注意事项 - 上述计算基于晶振频率为 11.0592 MHz 的前提下得出。如果使用不同的晶振频率,需重新调整参数。 - 若希望进一步提高精度,可通过增加外部校正机制或优化算法实现[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值