ATmega328 利用系统时钟预分频器降低时钟频率
本帖最后由 13560567638 于 2020-3-1 22:56 编辑ATmega328 可以通过设置时钟预分频寄存器CLKPR来得到分频的系统时钟。当需要的系统处理能力比较低时可以利用这个特性来降低功耗。预分频对所有时钟源都适用,并且影响 CPU 及所有同步外设的时钟频率。
当在预分频器设置转换时,系统时钟预分频器保证时钟系统不会出现毛刺。同时保证中频低于设置前后的时钟频率。脉动计数器使预分频器在未分频时钟频率下运行,这可能比CPU 时钟频率快。因此即使预分频器可读,我们也无法确定其状态,所以我们也无法得到准确的转换时间。 CLKPS 值的写入时间介于 T1 + T2 与 T1 + 2*T2 之间。在此间隔中,产生 2 个时钟边沿。其中 T1 为前一个时钟周期, T2 为新设置后相应的时钟周期。
为避免时钟频率的无意改变,对 CLKPS 位的写入必须按照如下步骤进行:
1. 将 CLKPCE 位写 "1”,而 CLKPR 寄存器的其他位写 "0”。
2. 在四个时钟周期内,将期望值写入 CLKPS,并在 CLKPCE 位写 "0”。
在改变预分频器设置时必须禁止中断,以保证在写入过程中不会出现中断。
时钟预分频寄存器- CLKPR
• Bit 7 – CLKPCE:
CLKPCE 位必须置"1”使能 CLKPS位。只有当CLKPR寄存器的其他位同时写"0”时, CLKPCE 位改变。CLKPCE 在
写入四个周期后或当 CLKPS 位写入后由硬件清零。在暂停周期中重新写 CLKPCE 位,既不扩展暂停周期,也不清除
CLKPCE 位。
• Bits 3..0 – CLKPS3..0:时钟预分频器选择位 3 - 0
这几位定义所选时钟源与内部系统时钟所分频因子。这几位写入运行时间来改变时钟频率以适应运行需要。当作为
MCU 主时钟输入分频器,使用分频因子时,所有同步外设速度将会下降。分频因子见 Table 17。
CKDIV8熔丝位决定CLKPS位的初始值。若CKDIV8未编程,CLKPS位复位为“0000”;若CKDIV8 已编程,CLKPS
位复位为 “0011”,给出启动时分频因子为 8。若所选时钟源频率大于当前工作状态下器件最大频率时,应利用该
特性分频。注意, CLKPS 位写入值不受CKDIV8 熔丝位设置影响。若所选时钟源频率大于当前工作状态下器件最大
频率,应用程序必须保证选择一个足够大的分频因子。芯片出厂时 CKDIV8 熔丝位已编程。
以下是ATmega328测试代码:
/*====================Pin8 连接低电平,开启时钟预分频器====================*/
void setup() {
pinMode(13, OUTPUT); //Pin13 为输出模式
pinMode(8, INPUT_PULLUP); //Pin8为输入上拉模式
/*在没有了解系统时钟预分频器之前, 不要删除if判断语句, 否则有可能造成烧录报错, Pin8 连接低电平开启时钟预分频*/
/*如果由于频率设置过低出现烧录报错, 只要把Pin8 悬空(建议连接高电平), 然后复位单片机, 再次烧录就可以解决问题*/
if(digitalRead(8) == 0) {
cli(); //禁止所有中断
CLKPR = 0b10000000; //时钟预分频器变化使能
CLKPR = 0b10; //时钟频率设置为4 分频
sei(); //重新启用中断
}
}
void loop() {
digitalWrite(13, !digitalRead(13));
delay(1000); //延时1秒,由于降频的原因变为延时4秒
}
/*====================Pin8 连接高电平,关闭时钟预分频器====================*/
解决烧录报错:
报错原因是时钟频率不符合要求造成的,主要出现在ArduinoISP作为烧录器的情况(ISP烧录器应该都有这个问题),关于如何把Arduino变成AVRISP烧录器网上有很多资料,这里不再赘述。Arduino开发版直接上传和TTL上传均不会出现报错,这与上传及烧录的原理有关,上传程序是依靠BootLoader自编程,而烧录是单片机自身的功能。当然,与MCU对SPI串行下载的频率要求也有关系,串行时钟 (SCK) 的高电平最小持续时间和低电平最小持续时间要满足如下要求:
高:> f ck < 12 MHz 时为 2 个 CPU 时钟周期, f ck >= 12 MHz 时为 3 个 CPU 时钟周期。
低:> f ck < 12 MHz 时为 2 个 CPU 时钟周期, f ck >= 12 MHz 时为 3 个 CPU 时钟周期。
从要求中可以看出,高低电平的最小持续时间分别为2个CPU时钟周期和3个CPU时钟周期,因此,取3个CPU时钟周期。SPI高电平时间等于3个CPU时钟周期、SPI低电平时间也等于3个CPU时钟周期,那么,1个SPI时钟周期应该等于6个CPU时钟周期,高低电平的持续时间相加才是1个SPI时钟周期。
假设: CPU时钟频率为16MHz,将CPU时钟频率256分频等于62500Hz (即 16000000/256=62500Hz)
ArduinoISP默认SPI时钟频率等于166666Hz (即 1000000/6=166666Hz)
62500Hz(CPU) < 166666Hz(SPI)
但是,根据要求SPI时钟频率必须小于等于CPU时钟频率的1/6(或CPU时钟频率的1/4)。
所以,SPI时钟频率应该小于等于62500/6=10416Hz,因此,需要修改SPI时钟频率。
那么,怎么修改ArduinoISP的SPI时钟频率呢?
打开Arduino -> 点击 "文件" -> "示例" -> "11.ArduinoISP" -> "ArduinoISP"
点击 "编辑" -> "查找" -> 寻找 "#define SPI_CLOCK"
把 #define SPI_CLOCK (1000000/6) 改为 #define SPI_CLOCK (62500/6)
SPI时钟频率越小烧录速度越慢,耐心等待...
重新上传ArduinoISP程序,然后再次烧录,发现问题已经迎刃而解。
到此已经可以放心删除if判断语句了!
降低时钟频率同时也可以降低工作电压,将大幅度的降低功耗。除了,利用系统时钟预分频器降低时钟频率,还可以通过修改熔丝位同样可以降低时钟频率,待续 ......
页:
[1]