如何在无浮点变量时计算ATmega32 Timer0的TCNT0初始值
纯整数运算实现ATmega32 Timer0 Normal模式延时参数计算
针对ATmega32无FPU的情况,我们可以把所有浮点公式转换为纯整数运算,完全避免float/double类型,从而减小代码体积。核心思路是将时间单位统一为微秒,利用整数运算技巧实现浮点公式中的取整、除法逻辑。
核心公式转换(从浮点到整数)
已知CPU频率为1MHz(对应原代码中的1000000.0),先明确整数版计算逻辑:
- 将输入的毫秒延时转换为微秒:
delay_us = 延时毫秒数 × 1000 - 计算单个Timer tick的微秒数:
tick_us = 分频系数(1MHz下,1个时钟周期为1微秒,分频后每个tick对应分频系数个时钟周期) - 单次Timer0溢出的最大延时:
max_overflow_us = 256 × tick_us(8位定时器最大计数256次) - 溢出次数计算(向上取整):
N = (delay_us + max_overflow_us - 1) / max_overflow_us(整数运算实现ceil(delay_us / max_overflow_us)) - 总需要的tick数:
total_ticks = delay_us / tick_us - 单次溢出所需tick数:
ticks_per_overflow = total_ticks / N - TCNT0初始值:
TCNT0_init = 256 - ticks_per_overflow
纯整数实现代码
#include <stdint.h> // 全局变量:记录需要的溢出次数(需根据代码环境调整定义) uint32_t global_ValueToReachCount; /* * @fn : calculatInitValueForTimer0 * * @params[0]: 延时毫秒数 * @params[1]: Timer0分频系数(如1, 8, 64, 256, 1024) * * @brief : 纯整数计算Timer0 Normal模式下的初始值,同时设置溢出次数 * * @return : TCNT0的初始值 */ static uint8_t calculatInitValueForTimer0(uint32_t args_u32TimeInMilliSeconds, uint16_t args_u8Prescalar) { // 转换延时为微秒,用uint64_t避免中间计算溢出 uint64_t delay_us = (uint64_t)args_u32TimeInMilliSeconds * 1000; // 计算单个tick的微秒数(1MHz CPU下直接等于分频系数) uint32_t tick_us = args_u8Prescalar; // 单次溢出的最大延时(微秒) uint64_t max_overflow_us = (uint64_t)256 * tick_us; uint8_t tcnt0_init = 0; if (delay_us <= max_overflow_us) { // 只需1次溢出 global_ValueToReachCount = 1; // 计算需要的tick数,初始值为256减去该值 uint32_t needed_ticks = delay_us / tick_us; tcnt0_init = 256 - (uint8_t)needed_ticks; } else { // 计算溢出次数(向上取整) global_ValueToReachCount = (delay_us + max_overflow_us - 1) / max_overflow_us; // 总tick数除以溢出次数,得到单次溢出需要的tick数 uint64_t total_ticks = delay_us / tick_us; uint16_t ticks_per_overflow = (uint16_t)(total_ticks / global_ValueToReachCount); tcnt0_init = 256 - ticks_per_overflow; } return tcnt0_init; }
关键细节说明
- 使用
uint64_t处理中间计算:避免大数值(如1秒延时+1024分频)导致的32位整数溢出 - 向上取整技巧:
(a + b - 1) / b是整数运算中实现ceil(a/b)的标准方法,无需浮点判断 - 多CPU频率适配:如果CPU频率不是1MHz,只需修改
tick_us的计算为tick_us = (uint64_t)args_u8Prescalar * 1000000 / F_CPU;(其中F_CPU定义为你的CPU频率,如#define F_CPU 8000000UL)
内容的提问来源于stack exchange,提问作者abdo Salm
相关产品推荐
相关产品推荐

