定时器(定时器0)——可定时任意时间的初始化函数
<p><strong>定时器0是16位定时器,40MHz下最大约能定时19ms,若配合8位预分频器,可组成24位定时器,最大约定时5s。</strong></p><h2>主要寄存器/控制位</h2>
<p>TM0PS(8位预分频器):不使用时,设置为0即可。</p>
<p>T0_CT(定时器/计数器选择位):0为定时器,1位计数器。</p>
<p>T0x12(定时器速度控制位):0为12分频模式(分频后可以定时更长),1为不分频模式。</p>
<p>TH0|TL0(定时器计数值):两个8位寄存器共同组成16位寄存器。</p>
<p>TMOD(定时器/计数器模式选择位):</p>
<p>0为16位自动重装载模式,即16位计数值溢出时,硬件自动为定时器赋予计数值,并重新开始计数(常用)</p>
<p>1为16位不自动重装载模式,当计数值溢出时,若不进行软件赋予计数值,将从0开始计数</p>
<p>2为8位自动重装载模式,只使用TL0一个8位寄存器,进行计数工作</p>
<p>3为不可屏蔽中断的16位自动重装载模式,与模式0相同,全场最高中断优先级,且不可屏蔽,常用于操作系统的系统节拍定时器</p>
<h2>重装载值计算(16位)</h2>
<p>手册中介绍的定时器周期T与16位重装载值的关系公式如下:</p>
<div class="language-math">T = {{65536 - } \over {SYSclk/(TM0PS + 1)}} \times T0x12</div>
<p>对我们而言,系统时钟SYSclk为已知变量,TM0PS和T0x12为预设置变量。</p>
<p>因此,可以通过等式变换得到:</p>
<div class="language-math">65536 - = {T \over {T0x12}} \times {{SYSclk} \over {(TM0PS + 1)}}</div>
<p>最终能够得到一个预期时间为自变量(秒),16位重装载值为因变量的公式:</p>
<div class="language-math"> = 65536 - ({{SYSclk \times T} \over {T0x12 \times (TM0PS + 1)}})</div>
<h2>定时器初始化函数</h2>
<p>综合以上所有条件,写出一个定时器0的初始化函数就不难了</p>
<p><img src="data/attachment/forum/202504/22/172628j238wob7fc7x35tz.png" alt="image.png" title="image.png" /></p>
<p>对于中断函数,这里作时基定时器:</p>
<p>1倍时基B_1T,每次溢出时置1;</p>
<p>10倍时基B_10T,溢出10次时置1;</p>
<p>以此类推.........</p>
<p><img src="data/attachment/forum/202504/22/172639jwznneppo8r8kaea.png" alt="image.png" title="image.png" /></p>
<h2>定时器应用</h2>
<pre><code class="language-c">// 这里使用16位重装载模式,12T分频,定时1ms
Timer0_Init(TIM_16BitAutoReload, TIM_CLOCK_12T, 1, TIM_ms); // 1ms定时
// 主循环中每秒+1,并使用数码管显示个位数,串口打印数值
if (B_1000T)
{
B_1000T = 0;
d++;
SMG_Show_Num(SEG3, d % 10, 0);
printf("count=%d\r\n", d);
}
</code></pre>
<p><strong>串口打印:1秒误差大约在10ms左右,1分钟误差大约在100ms左右</strong></p>
<p>接收←欢迎使用AI8051U开发板【火烛】!<br />
接收←count=1<br />
接收←count=2<br />
接收←count=3<br />
接收←count=4<br />
接收←count=5<br />
接收←count=6<br />
接收←count=7<br />
接收←count=8<br />
接收←count=9<br />
接收←count=10<br />
接收←count=11<br />
接收←count=12<br />
接收←count=13<br />
接收←count=14<br />
接收←count=15<br />
接收←count=16<br />
接收←count=17<br />
接收←count=18<br />
接收←count=19<br />
接收←count=20<br />
接收←count=21<br />
接收←count=22<br />
接收←count=23<br />
接收←count=24<br />
接收←count=25<br />
接收←count=26<br />
接收←count=27<br />
接收←count=28<br />
接收←count=29<br />
接收←count=30<br />
接收←count=31<br />
接收←count=32<br />
接收←count=33<br />
接收←count=34<br />
接收←count=35<br />
接收←count=36<br />
接收←count=37<br />
接收←count=38<br />
接收←count=39<br />
接收←count=40<br />
接收←count=41<br />
接收←count=42<br />
接收←count=43<br />
接收←count=44<br />
接收←count=45<br />
接收←count=46<br />
接收←count=47<br />
接收←count=48<br />
接收←count=49<br />
接收←count=50<br />
接收←count=51<br />
接收←count=52<br />
接收←count=53<br />
接收←count=54<br />
接收←count=55<br />
接收←count=56<br />
接收←count=57<br />
接收←count=58<br />
接收←count=59<br />
接收←count=60<br />
接收←count=61<br />
接收←count=62<br />
接收←count=63<br />
接收←count=64<br />
接收←count=65<br />
接收←count=66<br />
接收←count=67<br />
接收←count=68<br />
接收←count=69<br />
接收←count=70</p>
<p><strong>数码管演示</strong></p>
<video controls="controls" src="forum.php?mod=attachment&aid=94868"></video>
在嵌入式系统中,定时器的配置与使用是实现精确时间控制的关键。针对您提到的定时器0的初始化函数及其相关寄存器配置,以下将详细解析其工作原理及初始化步骤。
1. 定时器0的基本特性
定时器0是一个16位定时器,在40MHz的系统时钟(SYSclk)下,其最大定时时间约为19ms。若结合8位预分频器(TM0PS),可扩展为24位定时器,最大定时时间可达5s。这种灵活性使其适用于多种应用场景,如延时控制、PWM生成、事件计数等。
2. 主要寄存器及控制位
2.1 TM0PS(8位预分频器)
TM0PS用于对系统时钟进行分频,以延长定时器的定时范围。若不使用预分频器,可将其设置为0。
2.2 T0CT(定时器/计数器选择位)
0:定时器模式,定时器根据系统时钟计数。
1:计数器模式,定时器根据外部信号计数。
2.3 T0x12(定时器速度控制位)
0:12分频模式,系统时钟经过12分频后作为定时器时钟源,适用于需要较长定时时间的场景。
1:不分频模式,系统时钟直接作为定时器时钟源,适用于高精度定时。
2.4 TH0|TL0(定时器计数值)
TH0和TL0是两个8位寄存器,共同组成16位计数值。定时器从该值开始计数,直至溢出。
2.5 TMOD(定时器/计数器模式选择位)
0:16位自动重装载模式,计数值溢出时,硬件自动重装载初始值并重新计数。
1:16位不自动重装载模式,计数值溢出时,需软件手动重装载。
2:8位自动重装载模式,仅使用TL0进行计数,适用于较短定时。
3:不可屏蔽中断的16位自动重装载模式,与模式0类似,但具有最高中断优先级且不可屏蔽,常用于操作系统的系统节拍定时器。
3. 重装载值计算
定时器周期T与16位重装载值的关系公式如下:
\[ T = \frac{65536 - }{SYSclk/(TM0PS + 1)} \times T0x12 \]
其中,SYSclk为系统时钟频率,TM0PS为预分频器值,T0x12为分频模式。
通过等式变换,可得到重装载值的计算公式:
\[ = 65536 - \left( \frac{SYSclk \times T}{T0x12 \times (TM0PS + 1)} \right) \]
该公式可用于根据预期定时时间T计算TH0和TL0的初始值。
4. 初始化函数设计
以下是一个基于上述原理的定时器0初始化函数示例:
c
void Timer0Init(uint32t SYSclk, uint8t TM0PS, uint8t T0x12, float T) {
// 计算重装载值
uint16t reloadvalue = 65536 - (uint16t)((SYSclkT) / (T0x12(TM0PS + 1)));
// 设置预分频器
TM0PS = TM0PS; // 设置预分频器值
// 设置定时器模式
TMOD &= 0xFC; // 清除TMOD的低两位
TMOD |= 0x00; // 设置为16位自动重装载模式
// 设置定时器速度控制位
T0x12 = T0x12; // 设置分频模式
// 设置定时器计数值
TH0 = (uint8t)(reloadvalue >> 8); // 设置TH0
TL0 = (uint8t)(reloadvalue & 0xFF); // 设置TL0
// 启动定时器
TR0 = 1; // 启动定时器0
}
5. 使用示例
假设系统时钟为40MHz,预分频器为0,不分频模式,需要定时1ms,则初始化函数调用如下:
c
Timer0Init(40000000, 0, 1, 0.001);
6. 总结
通过合理配置定时器0的寄存器,结合预分频器和分频模式,可以实现从微秒到秒级的精确定时。上述初始化函数提供了灵活的配置方式,可根据具体需求调整参数,满足不同应用场景的定时需求。
[本文内容由国芯人工智能辅助生成,仅供参考] if( UsbOutBuffer == 'h' && UsbOutBuffer == 'e' && UsbOutBuffer == 'l' && UsbOutBuffer == 'l' && UsbOutBuffer == 'o' && UsbOutBuffer == '\r' && UsbOutBuffer == '\n' )
这里memcmp不好吗 Ayb_ice 发表于 2025-4-28 11:44
if( UsbOutBuffer == 'h' && UsbOutBuffer == 'e' && UsbOutBuffer == 'l' && UsbOutBuff ...
很不错{:qiang:},当然可以滴,写法有很多种。
页:
[1]