s3c2440芯片中一共有5个16位的定时器频率其中有4个定时器频率(定时器频率0~定时器频率3)具有脉宽调制功能,即他们都有个输出引脚,可以通过定时器频率来控制引脚周期性的高低电平变化定时器频率4没有输出引脚。上次脱机运行PWM测试程序实验的时候就用到了这块所以这次将PWM和定时器频率放在一起来学习。
定時器频率部件的时钟源为PCLK首先通过两个8位预分频器降低频率,定时器频率0和1共用第一个预分频器2,34共用第二个预分频器。
预分频器輸出接入第二级分频器可以生成5种分频信号(1/2,1/41/8,1/16TCLK),其中8位预分频器是可编程根据装载值来分频PCLK,值储存在TCFG0和TCFG1中
定时器频率内部控制逻辑工作流程如下:
定时器频率n的输出管脚TOUTn初始状态为高电平然后会两次反转,
也可以通过TCON寄存器设定其初始电平这样输出就完全反相了。
通过设置TCMPBn、TCNTBn可以设置TOUTn输出信号的占空比这样就是所谓的PWM。这里PWM的原理就鈈做介绍了
下面介绍定时器频率的几种重要寄存器,每一种我们都以定时器频率0为例
TCON寄存器位[3:0]、[11:8]、[15:12]、[19:16]、[22:20]分别用于定时器频率0~4,位[4]为死區使能位[7:5]为保留位。除了定时器频率4没有输出反转位外其他位功能相似,这里以定时器频率0为例加以说明位[0]开启停止位:0停止定时器频率,1开始定时器频率[1]手动更新位:0无用,1将TCNTBn/TCMPBn寄存器的值装入内部寄存器TCNTn\TCMPn中[2]输出反转:0不反转,1反转[3]自动加载:0不自动加载,1自動加载
下面就具体介绍如何实现PWM功能。
1、PWM是通过引脚TOUT0~TOUT3输出的而这4个引脚是与GPB0~GPB3复用的,因此要实现PWM功能首先要把相应的引脚配置成TOUT输出
2、再设置定时器频率的输出时钟频率,它是以PCLK为基准再除以用寄存器TCFG0配置的prescaler参数,和用寄存器TCFG1配置的divider参数
3、然后设置脉冲的具体宽喥,它的基本原理是通过寄存器TCNTBn来对寄存器TCNTn(内部寄存器)进行配置计数TCNTn是递减的,如果减到零则它又会重新装载TCNTBn里的数,重新开始計数而寄存器TCMPBn作为比较寄存器与计数值进行比较,当TCNTn等于TCMPBn时TOUTn输出的电平会翻转,而当TCNTn减为零时电平会又翻转过来,就这样周而复始因此这一步的关键是设置寄存器TCNTBn和TCMPBn,前者可以确定一个计数周期的时间长度而后者可以确定方波的占空比。由于s3c2440的定时器频率具有双緩存因此可以在定时器频率运行的状态下,改变这两个寄存器的值它会在下个周期开始有效。
4、最后就是对PWM的控制它是通过寄存器TCON來实现的,当不想计数了可以使自动重载无效,这样在TCNTn减为零后不会有新的数加载给它,那么TOUTn输出会始终保持一个电平(输出反转位為0时是高电平输出;输出反转位为1时,是低电平输出)这样就没有PWM功能了,因此这一位可以用于停止PWM
总的来说PWM功能其实就是对2440定时器频率的应用。
下面我们来分析上次脱机运行PWM测试程序中没有分析的Buzzer_Freq_Set函数函数如下:
这两句话的作用是让GPBCON寄存器最低两位为10,即配置GPB0为複用功能TOUT0作为PWM输出
rTCMPB0 = rTCNTB0>>1; 这里是配置计时器的比较缓冲寄存器,让比较值为初始值的一半即设定了PWM的占空比为50%。
这就完成了PWM的设置
当我们唍成试验退出时用到Buzzer_Stop函数,我们来看这个函数:
至此PWM蜂鸣器发声实验就分析完了后面使用蜂鸣器唱歌等实验原理相似,只不过调整声音頻率和对于声音频率的延时时长的控制后面不做分析了
选用通用定时器频率TIM5的CH1,其输入管腳为PA0在开发板上PA0连接按键,当按键按下输入高电平按键松开输入低电平,实验测量高电平的脉冲宽度
// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断 // 时钟分频因子 配置死区时间时需要用到 // 计数器计数模式,设置为向上计数 // 重复计数器的值没用到不用管 // 配置输入捕获的通道,需要根据具体的GPIO来配置 // 輸入捕获信号的极性配置 // 输入通道和捕获通道的映射关系有直连和非直连两种 // 输入的需要被捕获的信号的分频系数 // 输入的需要被捕获的信号的滤波系数 // 定时器频率输入捕获初始化 // 清除更新和捕获中断标志位 // 开启更新和捕获中断
首先判断定时器频率是否溢出定时周期,并做處理然后上升沿捕获时将计数器寄存器的值清零,中断改为下降沿触发下降沿捕获中断时,读取计数值改为上升沿触发,开始捕获標识清零结束捕获置1,。。。。
// 当要被捕获的信号的周期大于定时器频率的最长定时时定时器频率就会溢出,产生更新中断 // 這个时候我们需要把这个最长的定时周期加到捕获信号的时间里面去 // 自动重装载寄存器更新标志清0 // 存捕获比较寄存器的值的变量的值清0 // 当苐一次捕获到上升沿之后就把捕获边沿配置为下降沿 // 开始捕获标准置1 // 获取捕获比较寄存器的值,这个值就是捕获到的高电平的时间的值 // 當第二次捕获到下降沿之后就把捕获边沿配置为上升沿,好开启新的一轮捕获 // 开始捕获标志清0 // 捕获完成标志置1
// TIM 计数器的驱动时钟
// 获取捕獲寄存器值函数宏定义 // 捕获信号极性函数宏定义 // 定时器频率输入捕获用户自定义变量结构体声明
参考资料:野火《stm32库卡发实战指南》