MC9S12XS128tc1624 单片机机tc0=tcnt +31250什么意思

MC9S12XS128输出比较_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&10W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
MC9S12XS128输出比较
&&飞思卡尔,输出比较
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩2页未读,
定制HR最喜欢的简历
你可能喜欢MC9S12XS系列单片机的调试代码_图文_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&10W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
MC9S12XS系列单片机的调试代码
&&包括 1)ECT0通道输入捕捉(IC) 2)输出比较(OC)3)RTI实时中断4)AD采样 5)SCI通信
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩14页未读,
定制HR最喜欢的简历
你可能喜欢 上传我的文档
 上传文档
 下载
 收藏
该文档贡献者很忙,什么也没留下。
 下载此文档
飞思卡尔MC9S12XS128单片机各模块使用方法及寄存器配置
下载积分:1000
内容提示:飞思卡尔MC9S12XS128单片机各模块使用方法及寄存器配置
文档格式:DOCX|
浏览次数:402|
上传日期: 01:04:39|
文档星级:
全文阅读已结束,如果下载本文需要使用
 1000 积分
下载此文档
该用户还上传了这些文档
飞思卡尔MC9S12XS128单片机各模块使用方法及寄存器
关注微信公众号MC9S12XS128中文资料_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&10W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
MC9S12XS128中文资料
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩35页未读,
定制HR最喜欢的简历
你可能喜欢当前位置: >>
飞思卡尔MC9S12XS128单片机重点模块讲解
基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 ? 概述:飞思卡尔单片机的端口名称和 51 系列单片机有区别, 51 单片最经典的通用 I/O 口名称是 P0 口、P1 口、 P2 口、P3 口。而飞思卡尔 128 单片机是由 A 口、B 口、 K 口、E 口等标称的, 熟悉 51 单片的同学在此学习飞思卡尔单片时要知道变通,同样的对于学习其他单片机也是 一样的,先熟悉端口名称,再熟悉其端口功能,再熟悉其寄存器。C 语言的编程语法和算法 思路是通用的。 现在功能强悍一点的单片都在内部集成了很多现成的模块, 我们可以通过对 其模块寄存器编程配置我们需要的功能即可, 此处的 128 单片机就是这样一款单片机, 在此 我就我个人学习的一些心得写出来, 仅供交流与参考, 同时我也希望帮助新手能够很快得上 手。 具体更深层的内容大家还需要去参考芯片的技术手册和其他参考书。 以下我就分模块来 讲解, 大家在学习的过程中也需要一个模块一个模块的来学习和测试。 其实我个人觉得买过 来的开发板用途不是很大,因为很多端口被其在 PCB 设计时固化了,留给我们的端口并不 多,使用起来极不方便,所以我个人建议大家可以买个带有最小系统的模块,自己用排针和 插槽焊一个程序调试板,再焊一排共阴极的发光二极管(最好能发不同颜色光的) ,再焊几 个开关电路和按键电路即可。 我们在代码的各个位置通过点亮发光二极管来知道程序走到哪 一步了。下面我提供的测试例程也是这么来的,节省硬件就是节省开支啊,多动脑子,多想 办法可以克服很多困难的。 注: 一个寄存器的多个位可以一次性写入配置的, 但是为了使大家读程序理解方便我对寄存 器的每一位几乎一位一位配置的,我麻烦了,不过可以给大家读程序带来方便。第一章:PIM 模块(端口集成模块)一、端口主要功能概述: 1:端口 A、 B、K 作为通用的输入输出口使用 2:端口 E 整合了 1 个外部 IRQ(可屏蔽的 )和 XIRQ( 不可屏蔽的)中断输入模块 3:端口 T 整合了 1 个定时器 TIM 模块 4:端口 S 整合了 2 个 SCI(串行通信 )和 1 个 SPI(串行外设 )模块 5:端口 M 整合了 1 个 MSCAN(CAN 总线)模块 6:端口 P 连接到内部的 PWM( 脉宽调制)模块,即 PWM 信号可以通过 P 口输出,同时 P 口的输入也可以作为外部中断信号的输入。 7:端口 H 和 J 在作为通用输入输出口使用的同时也可以作为外部中断信号的输入口。 8:端口 AD 口整合了一个 16 通道的 ATD 模块即模拟量转数字量的模块。 二、通用输入输出口( GPIO )?以端口 A 和端口 B 为例讲解,以上是我截取的技术手册上的,从上来看 A 口和 B 口各 有 8 个口,且 A0-A7;B0-B7 全部作为 GPIO (通用输入输出口 )使用。此处 A 口和 B 口 使用方法是一样的,我姑且就以端口 A 来讲解。 A 口和 B 口作为通用输入输出口使用时我们只需要掌握 4 个寄存器即可。 PORTA (A 口? 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 数据寄存器) 、DDRA(A 口数据方向寄存器 )、PUCR(引脚上拉控制寄存器)、RDRIV(低 功耗驱动寄存器 )这些寄存器都是 8 位的寄存器,其名称可以直接在程序中使用,当然 也可以只使用其中的个别数据位。 DDRA 由如下 8 位构成,任何一位置 1 时对应端口为输出,置 0 时对应端口为输入。?这一点和 51 单片机的 I/O 口有区别,在典型的 51 单片中 P0 口内部没有上拉电阻,但作为 I/O 口使用时需要外接排阻。其他 P1-P3 口则可以直接作为双向口使用,51 单片在上电复位 后端口被默认的置 1.在 51 单片中端口的某一位置 0 时端口作为输出口使用,置 1 时作为输 入口使用。例如如果我们想把 P1 作为输出口使用时我们可以在程序开始时写 P1=0x00; 如果 我们想把 P1 口作为输入口使用时我们可以写 P1=0 这一点正好和飞思卡尔的 128 单片机 相反,另外 128 单片有专门的数据方向寄存器 DDRA 或者 DDRB 等来管理各个端口的输入 输出选择,51 单片没有。如果我们想把端口 A 作为输入口使用,我们只需写 DDRA=0x00; 即所有位都置 0,如果我们想把端口 A 作为输出口使用,我们只需要写 DDRA=0 即所有 位都置 1 ,而如 果我们想要 把端口 A 的高四 位做输入口 ,低 4 位做输 出口时我们 就 写 DDRA=0x0f; 当我们需要将该端口的某一位做输出或者输入口使用时只需要将该端口对应的 方向位置 1 或者置 0 即可。例如我们想把 A3 口作输入口, A4 口作输出口使用时我们只需 要写: DDRA_DDRA3=0; DDRA_DDRA4=1; 即可。 ? ? 对于数据方向寄存器的使用只要记住:置 1――输出 置 0――输入 PORTA 数据寄存器也是由 8 位组成,任何时候都可以对它进行读写操作。例如在 DDRA=0xff;A 口想全部输出高电平的话我们只要写 PORTA=0 想全部输出低电 平的话我们只要写 PORTA=0x00; 如果想让某一位输出高电平或者低电平的话我们只需要 将该端口对应的数据寄存器位置 1 或者置 0 即可,例如:PORTA_PA2=1; 此时 A2 口输出高 电平, PORTA_PA3=0; 此时 A3 口输出低电平。其他端口作为输入输出口使用时类似。 ? 对于数据寄存器的使用只要记住:置 1――高电平 置 0――低电平 ? PUCR 上拉控制寄存器是由 A、B、 E、K 口共用的,当端口作为输入口使用时用来控 制端口是否允许接上拉电阻。当端口做输出口使用时该寄存器无效。当我们将 A 口作输入口使用时需要设置 A 口内置上拉电阻时首先写 PUCR_PUPAE=1; 当我们将 B 口作输入口使用时需要设置 B 口内置上拉电阻时首先写 PUCR_PUPBE=1; 当我们将 E 口作输入口使用时需要设置 E 口内置上拉电阻时首先写 PUCR_PUPEE=1; 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 当我们将 K 口作输入口使用时需要设置 K 口内置上拉电阻时首先写 PUCR_PUPKE=1; ? ? 对于上拉控制寄存器的使用只要记住:置 1――设置上拉 置 0――禁止上拉 RDRIV 低功耗驱动寄存器,这个寄存器由 A、B、E、K 口共用。此低功耗驱动寄存器可以在任意时刻进行读、写操作。其中 RDPA、RDPB、RDPE、RDPK 作为低功耗选择位分别负责对 A 口、B 口、E 口、K 口低功耗驱动的选择,注意只有在该端 口被选择作为输出口使用时低功耗设置才有效, 作为输入口使用时是无效的。 一旦选择低功 耗后其输出功耗将近乎正常功耗的 1/5。例如我们想要把端口 A 作为低功耗输出,我们只需 在程序初始化的时候写入如下几条指令即可: DDRA=0 // 设置 A 口方向寄存器为数据输出 RDRIV_RDPA=1; // 选择 A 口为低功耗驱动 ? ? 对于低功耗驱动寄存器的使用只要记住: 置 1――选择低功耗输出 置 0――正常功耗 输出 到此为止关于端口作为 GPIO 使用时需要用到的四个端口寄存器我已经介绍完毕, 虽然 只以端口 A 为例讲解的,但是其他端口的使用方法是一样的,只是改一下寄存器名而 已,所以我们要学会举一反三。关于 GPIO 的使用最常见的就是输出高低电平或者读入 高低电平,不要小看这个高低电平,这个高低电平作为输出可以用来控制 LED 、加上 驱动之后可以用来控制电机、 可以用来驱动继电器等其他一些控制回路, 作为输入时可 以用来查询外部的传感或者触发信号, 可以来读取按钮或者来自键盘的信号等。 此处为 了方便我们就用它的输出来控制发光二极管的点亮,可以用来程序测试发光二极管, 达 到灯似流水的效果, 当年可以用程序把发光二极管控制随心所欲的时候 GPIO 你就入门 了。如下我给出我写的测试代码,这是针对 PORTB 即 B 口的,当你把 B0 到 B5 口按 顺序接到共阴极接法的 6 只发光二极管上时可以看到灯似流水的效果。 ? 源代码: (基于 128 单片机) /*------------------ 流水灯测试程序------------------------------*/ #include &hidef.h& // 头文件包含 #include &derivative.h& #define LED PORTB #define uchar unsigned char // 定义 LED 为 B 口 //宏替换#define uint unsigned int #define time 300 // 延时时间宏替换 /*--------------------- 延时函数---------------------------------*/ void delay(uint a) { uint i,j; for(i=0;i&a;i++) for(j=0;j&a;j++) ; 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 } /*--------------------- 主函数------------------------------------*/ void main(void) { DDRB=0x3f; LED=0x01; EnableI while(1) { delay(time); LED&&=1; delay(time); //延时 //高电平信号左移一位 //定义 B0-B5 口为输出 // 点亮第一只灯 //允许中断if(LED==0x20) //判断高电平信号是否移到第 6 位 LED=0x01; //重新赋初始值} } ? 源代码: (基于 STC52RC 单片机) #include &reg52.h& #define LED P1 // 选择 P1 口作为通用输出口 #define uchar unsigned char #define uint unsigned int void delay(uint a) { uint i,j; for(i=0;i&a;i++) for(j=0;j&a;j++) ; } void main() { LED=0x01; while(1) { LED=LED&&1; // 让高电平信号进行左移一位 // 点亮第一只发光二极管 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 delay(500); if(LED==0x80) LED=0x01; } } 综合以上的两段代码看在 52 单片机和 128 单片机上编程思路基本上没大的区别,唯一的区 别就是 128 单片机有数据方向寄存器来管理 I/O 口。 ? 将部分端口做输入口使用,另外一部分端口做输出口使用时:例如我们将 PORTB 的端 口 B7 用来做输入口,B0-B5 口做输出指示,测试代码如下:? 源代码: (基于 128 单片机) /*------------------------端口作为输入口使用时-------------------------------*/ /*-----程序功能:当端口 7 检测到高电平时 6 只发光二极管闪烁,否则发光二极管不亮 ----*/ #include &hidef.h& #include &derivative.h& #define INPUT PORTB_PB7 // 头文件包含 //将 B7 口作为输入信号的检测口#define uchar unsigned char //数据类型宏替换 #define uint unsigned int /*------------------------延时函数--------------------------------------*/ void delay(uint a) { uint i,j; for(i=0;i&a;i++) for(j=0;j&a;j++) ; } /*--------------------------指示灯闪烁函数-------------------------------*/ void light() { while(INPUT) { PORTB=0x3f; delay(500); PORTB=0x00; delay(500); } } //6 只灯全点亮 //延时一段时间 //6 只灯全熄灭 //延时一段时间 //判断输入电平的高低 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 /*------------------------------主程序 -------------------------------------*/ void main(void) { DDRB=0x3f; EnableI while(1) { light(); //设置端口 B 数据方向寄存器 B7 输入,B0-B5 输出 //中断允许} } 小结:其实以上这段小代码可以用来做故障检测及声光报警测试,故障时指示灯亮,故障消 除后指示灯不亮。第二章:PIT 模块概述:PIT 模块全称: Periodic Interrupt Timer 周期中断定时器,这个和我们熟悉的 51 单片 机的定时器 T0、T1 差不多,都是用来定时和计数的,区别仅在 51 单片机里的 T0 和 T1 定 时器都是 16 位的定时器,但分别可以拆成两个 8 位的使用。而此处的 PIT 定时器是由 2 个 8 位的微定时器和 4 个 16 位的定时器组合而成构成的 24 位定时器。51 单片机中 T0、T1 在 设置了计数值后进行加计数直到计数器溢出为止, 如果需要重复定时需要在中断里重装计数 初值。而 PIT 定时器正好相反,对它赋了计数初值后它由该初值做减计数,直到减为 0 时它 会产生溢出中断,此时计数初值会自动重装,重新开始计数,如此反复从而产生周期性的定 时中断。 ? PIT 定时器 ? 4 路定时器相互独立,可以独立使用,可以用来产生周期性溢出中断。 ? 定时器的溢出周期可以在 1 到 2 个时钟周期之间选择,此处若取 8 位微计数器的计数 值为 M,16 位计数器的值为 N,则 PIT 定时器的溢出周期 Tout =24( M + 1) × ( N + 1) (其中 f bus。例如对于一个 40MHz 的时钟信 0 ≤ M ≤ 255 ; 0 ≤ N ≤ 65535 ; f bus 为总线时钟频率) 号,则最大的溢出周期为 f bus =256 × 6ms 40 ×10 6? PIT 没有外部引脚,但是可以用来触发外围设备 内部连接图如下 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元由以上结果框图,我们可以很清晰地看到, 4 路 16 位的定时器可以和 2 个 8 位的微定时器 (time base 时基 0 和时基 1) 的任何一个串级组合成一个 24 位的定时器。 按照我的理解就跟 我们在数字电子技术这门课里学过的 74LS160 芯片串起来分频差不多,即时钟信号先触发 微定时器 0 或者微定时器 1 计数,再由此微定时器的溢出信号来做后面那个 16 位定时器的 时钟触发信号。可能这样解释不合适,但是这样的类比可以帮助自己理解。 ? PIT 定时器的相关寄存器学习 ? PIT Control and Force Load Micro Timer Register (PITCFLMT)PIT 控制和强制加载微定 时器寄存器?PITE:PIT 模块使能位,如果该位被清 0 则 PIT 模块被禁止,并且 PITTF 寄存器中的中 断标志位被清除, 当该位被置 1 后, 使能四路定时器中的任何一路其都会从相应的加载 寄存器的值开始减计数。 (置 0――关闭 PIT 模块节省电能,置 1――打开 PIT 模块) PITSWAI:PIT 等待模式下停止位,该位用于等待模式下的电源保护(置 0――PIT 模 块在等待模式下正常工作,置 1―― PIT 模块时钟停止,并且冻结 PIT 模块) PITFRZ :PIT 计数器冻结位,调试时冻结计数方便计数(置 0――PIT 模块在冻结模 式下正常工作,置 1―― PIT 在冻结模式下计数值被冻结) PFLMT1: 微定时器 1 的强制加载位: 这一位只有在 PIT 模块被启用, 并且微定时器正在 起作用时我们想要强行改变计数值时才有效(置 1――将 8 位微笑定时器寄存器的值强 制加载到相应的递减微计数器中,即重新设定计数初值。 置 0――无效) PFLMT0: 微定时器 0 的强制加载位: 这一位只有在 PIT 模块被启用, 并且微定时器正在 起作用时我们想要强行改变计数值时才有效(置 1――将 8 位微笑定时器寄存器的值强 制加载到相应的递减微计数器中,即重新设定计数初值。 置 0――无效) PIT Force Load Timer Register (PITFLT) PIT 强制加载定时寄存器? ? ??? 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 从以上寄存器示意图可以看到此寄存器有 4 个有效位, 这个有效位分别对应 4 路 16 位的定 时器,具体使用方法如下: ? PFLT[3:0]:这是定时器 0 到定时器 3 的强制加载位,只有 PIT 模块被使能,即 PITE 位 置 1,并且这四路定时器的相应使能位 PCE 被置 1 后,这时 PFLT 位置 1 才有效。该位 置 1 后,相应的 16 位定时寄存器的计数初值被加载到相应的 16 位定时减计数器中。 (置 1――有效 置 0――无效) ? PIT Channel Enable Register (PITCE) PIT 通道使能寄存器从以上寄存器示意图可以看到此寄存器有 4 个有效位,这个有效位分别对应着 4 路 16 位的 定时器的通道 0 到通道 3,具体使用方法如下: ? PCE[3:0]:这是定时器通道 0 到定时器通道 3 的相应使能位,如果该位清 0,则相应的 PIT 通道是禁用的, 并且相应的中断标志寄存器 PITTF 中的中断标志位也会被清 0,如果 PIT 模块被使能,即 PITE 位置 1,此时 PCE 置 1 的话,相应定时寄存器中的 16 位计数初值被加载到相应的 16 位定时减计数器中并开始进行减计数。 (置 1――相应的 PIT 通道被使能,置 0――相应的 PIT 通道被禁用) ? PIT Multiplex Register (PITMUX) PIT 多路选择寄存器从以上寄存器示意图可以看到此寄存器有 4 个有效位,这个有效位分别对应着 4 路 16 位的 定时器的通道 0 到通道 3,具体使用方法如下: ? PMUX[3:0]:这是定时器通道 0 到通道 3 的多路选择位,此处我们称 2 路 8 位微定时器 为 2 路时基,即时基 0 和时基 1。而 PMUX 位的设置就是为了让 4 路 16 位定时器选择 和时基 1 或者时基 0 组合成 24 位的定时器,一旦 PMUX 的值改变,相应 16 位定时器立马从一个时基切换到另外一个时基。 (置 1――相应的 16 位定时器连接到时基 1 置 0――相应的 16 位定时器连接到时基 0) ? PIT Interrupt Enable Register (PITINTE) PIT 中断使能寄存器从以上寄存器示意图可以看到此寄存器有 4 个有效位,这个有效位分别对应着 4 路 16 位的 定时器的通道 0 到通道 3,具体使用方法如下: ? PINTE[3:0] :这是 16 位定时器通道 0 到通道 3 相应的定时器溢出中断使能位,这些位 位使能后,一段相应中断标志寄存器的标志位置 1,就会产生中断服务请求。但是在中 断标志位不明确的情况下,PITNE 位有可能造成误入中断,所以我们在设置时最好先 清除相应的中断标志位, 再使能中断。 (置 1――使能相应通道的 PIT 中断 置 0――禁 止相应通道的 PIT 中断) PIT Time-Out Flag Register (PITTF) PIT 溢出标志寄存器? 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元从以上寄存器示意图可以看到此寄存器有 4 个有效位,这个有效位分别对应着 4 路 16 位的 定时器的通道 0 到通道 3,具体使用方法如下: ? PTF[3:0]:定时器通道 0 到通道 3 的溢出标志位,一旦由 16 定时器和 8 位微定时器做 时基而成的 24 位定时器的减计数器减到 0 的时候会将相应的 PTF 位置 1,通过写 1 将 该标志位清除 (特别注意这个和我们学的 51 系列单片机有不同的, 在 51 单片机中我们 通过写 0 来清除中断标志位,而此处是通过写 1) ,写 0 是无效的。但是一旦 PIT 模块 被禁用或者相应的 PIT 通道被关闭的时候,相应的标志位也是会被清除的。 (置 1――相应的 PIT 通道发生了减计数的溢出 置 0――相应的 PIT 通道未发生减计数的溢 出) ? PIT Micro Timer Load Register 0 to 1 (PITMTLD0C1) PIT 微定时器加载寄存器?从上图可知这两个寄存器对别是微定时器 0 和微定时器 1 的加载寄存器, 都是 8 位的寄 存器,加载值可以从 0x01 到 0xFF,对应十进制的 1 到 255(加载值为 0 无意义)写一 个新计数值到该寄存器后不会重新启动定时器, 直到微定时器的值减到 0 后, 该计数值 才会被加载到相应的减计数器中开始计数。 如果想要在程序中立即改变计数值我们可以?借助前面提到的强制加载位,如果不是特别需要,我们可以不用它们的强制加载位。 PIT Load Register 0 to 3 (PITLD0 C3) PIT 定时器 0 到 3 的加载寄存器这 4 个寄存器分别是 16 定时器 0 到定时器 3 的加载寄存器,使用方法与微定时器 8 位的加 载寄存器差不多,区别仅在它们是 16 的,加载值可以从 0x0001 到 0xFFFF ,即十进制的 1 到 65535。 写一个新计数值到该寄存器后不会重新启动定时器, 直到微定时器的值减到 0 后, 该计数值才会被加载到相应的减计数器中开始计数。 如果想要在程序中立即改变计数值我们 可以借助前面提到的强制加载位,如果不是特别需要,我们可以不用它们的强制加载位。 不 过为了保证数据的连续性,我们必须对该寄存器进行 16 位的存取,即进行以字为单位的读 写。 注意: 到此为止, 以上介绍的关于 PIT 模块的寄存器都是可以在任意时刻读也可以在任意时 刻写的, 以下最后介绍的一个寄存器是只能任意时刻读, 而对它进行写操作是无意义也是无 效的。 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 ? PIT Count Register 0 to 3 (PITCNT0C3) PIT 定时器 0 到 3 的计数寄存器这个就是定时器 0 到定时器 1 分别对应的 16 减计数寄存器,这个寄存器反应着当前计数器 的计数值,读这个寄存器必须在一个时钟周期里完成,并且必须以字(双字节)进行读取。 该寄存器只可以读,不能够写。 ? ? 测试例程: 在我们学习第一个 GPOI 模块时我们是让发光二极管按照我们预定的程序点 亮的,在此处我们可以利用 PIT 的定时功能让小灯隔一段时间点亮。 源代码: (基于 128 单片机)/*--------------------------系统的晶振是 16MHz----------------------------------*/ #include &hidef.h& #include &derivative.h& /*--------------------------端口定义 -------------------------------------------*/ #define LED_1 PORTB_PB0 #define LED_1_dir DDRB_DDRB0 #define LED_2 #define LED_2_dir PORTB_PB5 DDRB_DDRB5/*--------------------------变量定义 -------------------------------------------*/ #define uchar unsigned char #define uint unsigned int uint Time_count=0; uchar LED_flag=0; /*---------------------------延时函数 ------------------------------------------*/ void delay(uint a) { uint i,j; for(i=0;i&a;i++) for(j=0;j&a;j++) ; } /*---------------------------端口初始化----------------------------------------*/ void Port_initial() { LED_1_dir=1; LED_2_dir=1; } /*------------------------------PIT 模块初始化----------------------------------*/ void PIT_initial() //定义端口 B0 为输出 //定义端口 B5 为输出 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 { PITTF_PTF=0x0f; PITMTLD0=0x9f; PITLD0=0x1387; PITINTE_PINTE0=1; PITMUX_PMUX0=0; PITCE_PCE0=1; PITCFLMT_PITE=1; //清除中断标志位 //设置 8 位微定时器 0 计数初值 //设置 16 位定时器 0 的计数初值 //允许定时器 0 的通道中断 //将定时器 0 和微定时器 0 连接 //打开定时器 0 的通道 //使能 PIT 模块} //定时周期 =(159+1)*(MHz=500ms=0.5s /*---------------------------------指示灯函数----------------------------------*/ void light_1() // 指示灯 1 { uchar i=5; LED_2=0; while(i--) { LED_1=1; delay(500); LED_1=0; delay(500); } } //关闭指示灯 2void light_2() { uchar i=5; while(i--) {// 指示灯 2LED_2=1; delay(500); LED_2=0; delay(500); } } /*---------------------------------PIT 通道 0 中断服务程序--------------------------*/ #pragma CODE_SEG __NEAR_SEG NON_BANKED 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 void interrupt 66 PIT_0 ( ) { Time_count++; if(Time_count==50) { LED_flag=1; Time_count=0; } PITTF_PTF0=1; } /*----------------------------------- 主程序-------------------------------------*/ void main(void) { Port_initial(); PIT_initial(); //端口初始化 //PIT 模块初始化 //清除中断标志位 // 设置标志位 //周期计数值清 0 //中断次数加 1 即定时周期增加一个EnableI // 允许中断 while(1) { light_2(); // 正常情况下指示灯 2 闪烁 // 定时到了之后关闭指示灯 2,指示灯 1 闪烁if(LED_flag==1) { LED_flag=0; light_1(); } } }第三章:PWM 模块概述:这一部分我们来学习一下 PWM 模块,即脉宽调制模块,PWM 模块很有用,在实际 应用中我们可以用它来得到一系列我们想要的不同频率和占空比的脉冲信号, 用这些脉冲信 号我们可以来控制开关管,从而对直流电压进行斩波控制,得到不同的平均电压,这个可以 用来对直流电机进行调速。另外对于小负载可以用 PWM 直接驱动,例如我们可以用 PWM 波来控制发光二极管的闪烁, 用作系统的指示灯用。 对于获得到不同频率和占空比的脉冲信 号我们可以拿来控制例如步进电机的细分驱动器或伺服电机等。 总之, PWM 脉冲非常有用, 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 但是我们很多 51 系列单片机没有这样的模块,如果需要用时就需要自己在程序里用软件的 方法来实现,比如用 T0 或者 T1 定时器的中断控制信号电平的翻转来实现,但是对 CPU 的 利用有一定的影响。不过现在一些用于工业控制场合的单片机都自带 PWM 模块了,此处的 128 单片机就是自带 PWM 模块的,只要在程序里启动 PWM 模块后,就可以让它独立工作 了,不占用 CPU 大量的资源。学习 PWM 模块也是需要熟悉它的相关寄存器和配置方法。 128 单片机的 PWM 模块包括以下特点: ? 有 8 个独立的 PWM 通道,可以通过编程进行输出波形周期和占空比的配置 ? ? ? ? ? ? 每个 PWM 通道都有独立的定时器,可以通过编程对它进行使能和禁用 通过软件编程来选择 PWM 通道输出波形的极性 ,选择左对齐还是中心对齐方式 可以分成 8 个 8 位的 PWM 通道使用,也可以通过合并联接成 16 位的通道使用 四个宽频的时钟源选择,分别是 A、B、SA、SB 时钟源,编程选择波形的起始电平 带有紧急关闭功能 模块结构图如下从结构图上我们可以了解到当系统的总线时钟进入模块后我们可以通过相关的控制寄存器 和选择寄存器对时钟信号进行分配。然后送给 8 个 PWM 通道,这个 8 个 PWM 通道可以有 使能、极性、对齐方式等寄存器来控制,最后可以有 8 路独立的 PWM 波形的输出。接下来 我们就来学习一下它的几个相关寄存器的使用。 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 ? PWM Enable Register (PWME) 通道使能寄存器每个 PWM 通道都对应一个使能位来开启和关闭 PWM 通道,如上 PWME0 对应通道 0,依 次类推。一旦 PWMEx(其中 x 表示 0―― 7)置 1 后,相应的 PWM 输出立即生效,但是 PWM 波形的需要等到时钟源的下一个周期才正常输出。原因是介于 PWMEx 位和时钟源的 同步机制。注意:使能 PWM 通道后的第一个 PWM 波形是不规则的。 ? PWME7 通道 7 的脉宽使能位: (置 0――通道关闭 置 1――通道打开) ? ? ? ? ? ? ? ? PWME6 通道 6 的脉宽使能位: (置 0――通道关闭 置 1――通道打开) 当通道 6 和通 道 7 联合成 16 位通道使用时,联合后信号从通道 7 输出 PWME5 通道 5 的脉宽使能位: (置 0――通道关闭 置 1――通道打开) PWME4 通道 4 的脉宽使能位: (置 0――通道关闭 置 1――通道打开) 当通道 4 和通 道 4 联合成 16 位通道使用时,联合后信号从通道 5 输出 PWME3 通道 3 的脉宽使能位: (置 0――通道关闭 置 1――通道打开) PWME2 通道 2 的脉宽使能位: (置 0――通道关闭 置 1――通道打开) 当通道 2 和通 道 3 联合成 16 位通道使用时,联合后信号从通道 3 输出 PWME1 通道 1 的脉宽使能位: (置 0――通道关闭 置 1――通道打开) PWME0 通道 0 的脉宽使能位: (置 0――通道关闭 置 1――通道打开) 当通道 0 和通 道 1 联合成 16 通位道使用时,联合后信号从通道 1 输出 PWM Polarity Register (PWMPOL) PWM 极性寄存器这个寄存器用来控制相对应的 8 个通道输出的 PWM 波形的起始极性,例如 PPOL0 用来控 制通道 0 的波形的起始极性, 如果该位置 1, 则相应的通道在一个周期的起始先输出高电平, 等到占空计数值到了之后信号再输出低电平。如果该位置 0,则相应的通道在一个周期的起 始先输出低电平, 等到占空计数值到了之后信号再输出高电平。 这个寄存器可以再任何时候 进行读或者写,但是需要注意的是一旦 PWM 波形已经输出,突然改变其极性可能造成波形 的畸变。 (PPOL[7:0] 置 1――起始输出高电平,占空计数值到了后再拉到低电平 ――起始输出低电平,占空计数值到了后再拉到低电平 ) ? PWM Clock Select Register (PWMCLK) PWM 时钟选择寄存器 置0每个 PWM 通道都有 2 个时钟作为时钟源的选择。 ? PCLK7 通道 7 的时钟源选择位 (置 0――通道 7 选择时钟 B 作为时钟源 ? ? 通道 7 选择时钟 SB 作为时钟源) PCLK6 通道 6 的时钟源选择位 (置 0――通道 6 选择时钟 B 作为时钟源 通道 6 选择时钟 SB 作为时钟源) PCLK5 通道 5 的时钟源选择位 (置 0――通道 5 选择时钟 A 作为时钟源置 1―― 置 1―― 置 1―― 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 通道 5 选择时钟 SA 作为时钟源) ? ? ? ? ? ? PCLK4 通道 4 的时钟源选择位 (置 0――通道 4 选择时钟 A 作为时钟源 通道 4 选择时钟 SA 作为时钟源) PCLK3 通道 3 的时钟源选择位 (置 0――通道 3 选择时钟 B 作为时钟源 通道 3 选择时钟 SB 作为时钟源) PCLK2 通道 2 的时钟源选择位 (置 0――通道 2 选择时钟 B 作为时钟源 通道 2 选择时钟 SB 作为时钟源) PCLK1 通道 1 的时钟源选择位 (置 0――通道 1 选择时钟 A 作为时钟源 通道 1 选择时钟 SA 作为时钟源) PCLK0 通道 0 的时钟源选择位 (置 0――通道 0 选择时钟 A 作为时钟源 通道 0 选择时钟 SA 作为时钟源) PWM Prescale Clock Select Register (PWMPRCLK) 置 1―― 置 1―― 置 1―― 置 1―― 置 1――PWM 预分频时钟选择寄存器由图可知,该寄存器的第 3 位和第 7 位是无效位。 ? PCKB[2:0] : 时钟 B 的预分频选择位,时钟 B 作为通道 2、3、6、 7 的时钟源,PCKB[2:0] 可以来配置时钟 B 的时钟频率。配置表格如下:由表格可知最后时钟 B 的时钟频率可以由总线时钟 1 分频、2 分频、4 分频直至 128 分频获 得,其他配置类似。?PCKA[2:0] :时钟 A 的预分频选择位, 时钟 A 作为通道 0、 1、 4、 5 的时钟源, PCKA[2:0] 可以来配置时钟 A 的时钟频率。配置表格如下: 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元由表格可知最后时钟 A 的时钟频率可以由总线时钟 1 分频、2 分频、4 分频直至 128 分频获 得,其他配置类似。 ? PWM Center Align Enable Register (PWMCAE) PWM 中央对齐使能寄存器这个 8 位的寄存器用来选择相应 PWM 通道输出的波形的对齐方式是中央对齐还是左对齐。 注意:只有相应的通道关闭的时候写这个 8 位寄存器才会生效。 ? CAE[7:0]:置 0――输出左对齐 置 1――输出中央对齐 ? 左对齐如下:?中央对齐如下: 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 ? PWM Control Register (PWMCTL) PWM 控制寄存器?CON67:通道 6 和通道 7 的联接控制位,置 0――通道 6 和通道 7 被分成两个 8 位的 PWM 通道使用。置 1――通道 6 和通道 7 联接起来作为一个 16 位的 PWM 通道使用, 通道 6 作高位字节,通道 7 作低位字节,通道 7 的输出引脚被作为 16 位 PWM 波形的 输出引脚。 通道 7 的时钟选择位决定时钟源的选择, 通道 7 的极性选择位决定波形的极?性,通道 7 的使能位使能 PWM 的输出,通道 7 的中央对齐选择位决定对齐模式。 CON45:通道 4 和通道 5 的联接控制位,置 0――通道 4 和通道 5 被分成两个 8 位的 PWM 通道使用。置 1――通道 4 和通道 5 联接起来作为一个 16 位的 PWM 通道使用, 通道 4 作高位字节,通道 5 作低位字节,通道 5 的输出引脚被作为 16 位 PWM 波形的 输出引脚。 通道 5 的时钟选择位决定时钟源的选择, 通道 5 的极性选择位决定波形的极 性,通道 5 的使能位使能 PWM 的输出,通道 5 的中央对齐选择位决定对齐模式。?CON23:通道 2 和通道 3 的联接控制位,置 0――通道 2 和通道 3 被分成两个 8 位的 PWM 通道使用。置 1――通道 2 和通道 3 联接起来作为一个 16 位的 PWM 通道使用, 通道 2 作高位字节,通道 3 作低位字节,通道 3 的输出引脚被作为 16 位 PWM 波形的 输出引脚。 通道 3 的时钟选择位决定时钟源的选择, 通道 3 的极性选择位决定波形的极 性,通道 3 的使能位使能 PWM 的输出,通道 3 的中央对齐选择位决定对齐模式。 CON01:通道 :0 和通道 1 的联接控制位,置 0――通道 0 和通道 1 被分成两个 8 位的 PWM 通道使用。置 1――通道 0 和通道 1 联接起来作为一个 16 位的 PWM 通道使用, 通道 0 作高位字节,通道 1 作低位字节,通道 1 的输出引脚被作为 16 位 PWM 波形的 输出引脚。 通道 1 的时钟选择位决定时钟源的选择, 通道 1 的极性选择位决定波形的极?? ? ?性,通道 1 的使能位使能 PWM 的输出,通道 1 的中央对齐选择位决定对齐模式。 PSWAI:置 1――关闭了预分频器的输入时钟,可以让 MCU 进入等待模式后实现低功 耗。置 0――在 MCU 进入等待模式后,允许时钟进入预分频器 PFREZ : 置 0――冻结模式下允许 PWM 继续 置 1――冻结模式下关闭 PWM 的输入 到预分频器的时钟,这对于仿真比较有利 PWM Scale A Register (PWMSCLA) PWM 时钟 A 的分频寄存器通过这个 8 位寄存器的值可以将 A 时钟分频得到 SA 时钟,其分频时钟公式计算如下: Clock SA = Clock A / (2 * PWMSCLA) 注意: 当 PWMSCLA = 0x00 时, 其值被认为是满额的 256,因此时钟 A 除以了 512 得到 SA 时钟。 ? PWM Scale B Register (PWMSCLB) PWM 时钟 B 的分频寄存器通过这个 8 位寄存器的值可以将 B 时钟分频得到 SB 时钟,其分频时钟公式计算如下: 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 Clock SB= ClockB / (2 * PWMSCLB) 注意:当 PWMSCLB = 0x00 时,其值被认为是满额的 256,因此时钟 B 除以了 512 得到 SB 时钟。 ? PWM Channel Counter Registers (PWMCNTx) PWM 通道计数寄存器每个 PWM 通道都有一个对应的 8 位的加 /减计数器以选定的时钟源的频率工作,这些计数 器在任何时候都可以被读取,并且不影响 PWM 的正常输出和其自身的计数,在左对齐模式 下计数值从 0 计到周期寄存器的设置值, 在中央对齐模式下计数值从 0 计到周期寄存器的设 置值再返回到 0。对该寄存器写入任何值都会引起它的复位到 0,计数方向可以被设置成向 上计数。 当通道关闭后相应的计数器就会停止计数。 在 16 位通道的联合模式下, 16 位写入, 或者 8 位写入到其高位字节或者地位字节都会引起该计数器的复位到 0, 当然读取该计数值 的时候为了保持数据的连续性采取 16 位的读取方式。 ? PWM Channel Period Registers (PWMPERx) PWM 通道周期寄存器这个寄存器的值决定了相应 PWM 通道的周期,周期计算方式如下: ? 左对齐输出时: PWMxPeriod=ChannelClockPeriod*PWMPERx 即: PWM 周期 =通道时钟周期*周期寄存器的值 ? ? 中央对齐输出时: PWMx Period = Channel Clock Period * (2 * PWMPERx) 即: PWM 周期 =通道时钟周期*(2*周期寄存器的值) PWM Channel Duty Registers (PWMDTYx) 通道占空比寄存器8 个 PWM 通道都有一个专用的占空比寄存器,例如:通道 0 对应的寄存器 PWMDTY0, 通 道 1 对应的寄存器 PWMDTY1。是该寄存器是个 8 位的寄存器,其值决定了相关 PWM 波 的占空比。 在数字电子技术这门课里我们了解到一个周期脉冲中高电平所占的时间与周期的 比值就是占空比。由于 PWM 通道采用的双缓冲的结构,所以一旦通道打开后我们改变占空 比寄存器的计数值时,这种改变是不会立即生效的,必须满足如下三个条件才行: 1.在一个有效周期的末尾,因为下一个时钟周期会接踵而至,所以改变几乎是立即生 效的。 2.通道计数器被复位到 0 3.通道被关闭 实际上因为时钟频率很高, 所以我们在程序中启动 PWM 后在任何位置改变占空比寄存器的 值后几乎能立即看到效果, 这个在对 DC 电动机进行 PWM 调速时就可以看出来。 简而言之, 我们在程序初始化时启动 PWM 模块后,在后续程序中可以单独改变占空比来调节波形。 注意:取决于 PWM 极性寄存器中对波形极性的设置,占空比寄存器是在维持高电平或者低 电平的持续时间。如果极性位被置 1,那么 PWM 波形起始输出高电平,当占空比寄存器的 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 计数值到达之后波形再拉低到低电平。 如果极性位被置 0, 那么 PWM 波形起始输出低电平, 当占空比寄存器的计数值到达之后波形再拉高到高电平, 所以此时占空比寄存器的计数值就 是低电平的持续时间。 占空比的计算公式如下: ? Polarity = 0 (PPOL x =0) (极性为 0 时) Duty Cycle = [(PWMPERx-PWMDTYx)/PWMPERx] * 100%?Polarity = 1 (PPOLx = 1) (极性为 1 时) Duty Cycle = [PWMDTYx / PWMPERx] * 100% PWM Shutdown Register (PWMSDN) PWM 关闭寄存器?这个寄存器提供了 PWM 模块在紧急情况下的通道关闭功能。为了使操作生效,通道 7 的有 效电平值至少持续 2 个时钟周期。 ? PWMIF :PWM 中断标志位, 这一位是反映通道 7 输入引脚上有效电平到无效电平的跳 变或者无效电平到有效电平的跳变。简单地讲就是反映上升沿或者下降沿的。通过写 1 来清除该标志位,写 0 是无效的。 (置 0――通道 7 输入引脚上没有发生电平信号的改 变 置 1――通道 7 输入引脚上发生了电平信号的改变) PWMIE: PWM 中断使能位(置 0――关闭 PWM 中断 置 1――使能 PWM 中断) PWMRSTRT:PWM 重启位,向该位写 1 会重启 PWM 各通道 PWMLVL:PWM 关闭输出电平控制位,一旦 PWM 通道被紧急关闭时,由该位控制各 通道被强制输出高电平或低电平。 (置 0――紧急关闭时 PWM 各通道强制输出低电平 置 1――紧急关闭时 PWM 各通道强制输出高电平) PWM7IN: PWM 通道 7 的输入状态位, 这一位反映了当前 PWM 通道 7 对应引脚的输入 状态。 PWM7INL:通道 7 对应的 PWM 通道关闭有效电平位,在紧急情况下这一位决定了关 闭 PWM 通道所需的有效电平位。 (置 0――低电平有效 置 1――高电平有效) PWM7ENA:PWM 紧急关闭使能位,如果该位置 1,通道 7 的引脚被强制为输入,启动 紧急关闭功能,此时与之相应的功能位才会生效。 (置 0――PWM 紧急关闭功能禁用 置 1――开启紧急关闭功能) 到此为止与 PWM 模块相关的寄存器全部介绍完毕,下面我们就来测试一下该模块,用 PWM 模块来产生一定频率和占空比的波形来控制发光二极管的闪烁。 PWM 模块初始化使用顺序如下: 1.配置 PWM 通道极性 2.选择通道的时钟源 3.选择分频值 4.配置 PWM 通道对齐方式 5.配置通道周期寄存器 6.配置通道占空比寄存器? ? ?? ? ?? ? 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 7.开放相应通道,使能模块 ? 源代码: (基于 128 单片机) 8 位通道的使用 /*---------------------PWM 模块的 8 位通道的使用-------外部晶振 16MHz------------------*/ /*――PWM 通道 0 接蓝色指示灯――PWM 通道 1 接黄色指示灯――端口 B0 接红色指示灯 -------------*/ /*程序启动后端口控制的红色指示灯恒定闪烁, PWM 通道 0 控制的指示灯以固定频率闪烁, PWM 通道 1 控制的指示灯通过改变占空比逐渐变亮,再逐渐变暗--------------------------------------*/ #include &hidef.h& #include &derivative.h& #define uint unsigned int #define uchar unsigned char #define time 300 //宏替换#define LED PORTB_PB0 // 定义端口 B0 为指示灯控制端口 #define LED_dir DDRB_DDRB0 //定义端口 B0 的方向控制位 /*---------------------------- 延时程序--------------------------------------------*/ void delay(uint a) { uint i,j; for(i=0;i&a;i++) for(j=0;j&a;j++) ; } /*---------------------------- 指示灯函数------------------------------------------*/ void light() { uchar i=5; while(i--) { LED=1; delay(time); LED=0; delay(time); } } /*------------------------------PWM 模块初始化-------------------------------------*/ void PWM_initial() 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 { PWMPOL_PPOL0=1; PWMPOL_PPOL1=1; PWMCLK_PCLK0=1; // 通道 0 极性起始选择高电平 // 通道 1 极性起始选择高电平 //通道 0 选择 SA 作为时钟源PWMCLK_PCLK1=1; //通道 1 选择 SA 作为时钟源 PWMPRCLK=0x04; //时钟 A 的频率为总线时钟 16 分频获得 ,clock_A=16/16=1MHz PWMCAE_CAE0=1; //通道 0 波形中央对齐 PWMCAE_CAE1=1; PWMSCLA=200; PWMPER0=200; PWMPER1=50; PWMDTY0=100; PWMDTY1=0; PWME_PWME0=1; PWME_PWME1=1; } /*----------------------------------- 端口初始化------------------------------------*/ void Port_initial() { LED_dir=1; } /*------------------------------------主程序 ---------------------------------------*/ void main(void) { Port_initial(); // 定义占空比变量 //端口初始化 //定义 BO 口为输出口 //通道 1 波形中央对齐 //clock_SA=1MHz/(2*200)=2.5kHz 通道周期 =0.4ms //通道 0 的 PWM 周期=0.4*2*200=160ms //通道 1 的 PWM 周期=0.4*2*50=40ms //通道 0 的占空比 =PWMDTY0/PWMPER0=50% //通道 0 的占空比 =PWMDTY0/PWMPER0=0% // 打开 PWM 通道 0 // 打开 PWM 通道 0PWM_initial(); //PWM 初始化 EnableI // 允许中断 while(1) { for(duty=0;duty&50;duty+=1) { PWMDTY1= light(); } //改变通道 1 的占空比,递增 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 for(duty=50;duty&0;duty-=1) { PWMDTY1= light(); } } //改变通道 1 的占空比,递减} ? 源代码( 128 单片机)两个 8 位通道联接成一个 16 位通道使用/*-----------------------------联接通道 0 和通道 1 组成一个 16 位的通道 --------------------*/ #include &hidef.h& #include &derivative.h& /*-------------------------------PWM 模块初始化--------------------------------------*/ void PWM_initial() { PWMCTL_CON01=1; PWMPOL_PPOL1=1; PWMCLK_PCLK1=1; PWMPRCLK=0x04; PWMSCLA=20; PWMCAE_CAE1=1; PWMPER01=50000; PWMDTY01=25000; PWME_PWME1=1; } /*---------------------------------主程序 -------------------------------------------*/ void main(void) { PWM_initial(); EnableI while(1); //联接通道 0 和通道 1 组成 16 位通道, 由通道 1 输出控制 //设置通道 1 极性为高电平 //设置通道 1 为 SA 时钟 //设置 A 时钟频率 ,clock_A=16MHz/16=1MHz //设置 SA 时钟频率,clock_SA=1/(2*20)=0.025MHz=40us //设置通道 1 为中央对齐 //PWM 周期=40us*50000=2s //设置 PWM 占空比= PWMDTY01/PWMPER01=50% // 打开 PWM 通道 1//PWM 初始化 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 } ? 熟悉了上面两种 PWM(8 位通道和 16 通道)的使用方法后我们再熟悉一下它深层次的 引用:开两路时钟源分别配置,带有中断并且可以随时关闭所有 PWM 通道的输出, 另 外一旦关闭信号消失后 PWM 通道自动重启,输出正常。请看我写的如下这段代码, 大 家请记住,再简单的代码尽可能写得规范一点,便于阅读和维护。我不敢说我写的代码 有多么精美,但是我个人认为层次很清晰,分模块的。 ? 源代码( 128 单片机) /*程序功能:用 B0 口和 B1 口控制 2 个指示灯做程序指示,即指示灯 1 做主程序指示 B1 口做中断服务程序指示。再由通道 0 和通道 2 的两路 PWM 波信号控制另外 2 个指示 灯以不同频率得闪烁,通道 7 做为紧急关闭的输入口接到一个可以供应高低电平的 开关上,通过开关来紧急关闭两路 PWM 波,同时我在主程序中设置了重启 PWM 通道 的程序,所以一旦关闭信号消除, PWM 通道会重新启动,即两路指示灯会重新闪烁 */ #include &hidef.h& #include &derivative.h& #define LED_1 PORTB_PB0 #define LED_2 PORTB_PB1 #define #define #define uchar uint time unsigned char unsigned int 500 //头文件包含 //定义端口 B0 口为指示灯控制口 //宏替换 //延时宏替换/*------------------------------功能子函数申明--------------------------------------*/ void delay(uint Time); void light_1(); void light_2(); void Port_initial(); void PWM_initial(); /*------------------------------------主程序 ---------------------------------------*/ void main(void) { Port_initial(); PWM_initial(); EnableI while(1) { PWMSDN_PWMRSTRT=1; light_1(); //重启 PWM 通道 //端口初始化 //PWM 初始化//指示灯 1 闪烁 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元} } /*------------------------------------PWM 中断服务程序-------------------------------*/ #pragma CODE_SEG __NEAR_SEG NON_BANKED void interrupt 57 PWM_INT() { LED_1=0; light_2(); } /*------------------------------------功能子函数------------------------------------*/ /*---------------------------延时函数 ------------------------------------------*/ void delay(uint Time) { uint i,j; for(i=0;i&Ti++) for(j=0;j&Tj++) ; } /*---------------------------指示灯函数-----------------------------------------*/ void light_1() { uchar cycle_time=4; while( cycle_time--) { LED_1=1; delay(time); LED_1=0; delay(time); } } //定义循环次数 //关闭指示灯 1 //指示灯 2 闪烁 //清中断标志位PWMSDN_PWMIF=1;void light_2() 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元{ uchar cycle_time=8; while( cycle_time--) { LED_2=1; delay(300); LED_2=0; delay(300); } } /*---------------------------端口初始化-----------------------------------------*/ void Port_initial() { DDRB=0x03; } /*------------------------------PWM 初始化---------------------------------------*/ void PWM_initial() // 晶振为 16MHz { PWMPOL_PPOL0=1; PWMPOL_PPOL2=1; PWMCLK_PCLK0=1; PWMCLK_PCLK2=1; PWMPRCLK=0x44; PWMCAE_CAE0=1; PWMCAE_CAE2=1; PWMSCLA=100; PWMSCLB=100; PWMPER0=100; PWMPER2=250; PWMDTY0=50; PWMDTY2=125; PWME_PWME0=1; PWME_PWME2=1; PWMSDN_PWM7ENA=1; PWMSDN_PWMIE=1; PWMSDN_PWM7INL=1; PWMSDN_PWMLVL=1; //设置通道 0 起始极性高电平 //设置通道 2 起始极性高电平 //设置通道 0 选择 SA 做时钟源 //设置通道 2 选择 SB 做时钟源 //A 、B 时钟为总线时钟 16 分频=16MHz/16=1MHz //设置通道 0 波形中央对齐 //设置通道 2 波形中央对齐 //设置 SA 时钟分频系数为 100,SA=1/(2*100)=5kHz=0.2ms //设置 SB 时钟分频系数为 100,SA=1/(2*100)=5kHz=0.2ms //通道 0 PWM 周期=100*0.2ms=20ms //通道 2 PWM 周期=100*0.2ms=20ms //通道 0 占空比 =PWMDTY0/PWMPER0=50% //通道 2 占空比=PWMDTY2/PWMPER2=50% //打开通道 0 //打开通道 2 //打开 PWM 紧急关闭功能 //打开 PWM 中断 //高电平有效,即通道 7 输入高电平关闭 PWM 通道 //通道关闭时强制输出高电平 //定义 B0-B1 口为输出 //定义循环次数 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 }第四章:TIM 模块(定时器模块)其实我们在前面已经学习了一个定时器模块了, 周期中断定时器。 这里我们再来学习一下另 外一个定时器模块, TIM 模块,可能大家会好奇这两者有区别吗?当然有,不过对于定时 用的话区别不大, 但是这个模块特有的功能是周期中断定时器模块无法比拟的, 等学习完大 家测试过后就会有体会了,下面我们就来学一下 TIM 模块,老方法,先熟悉大致功能再熟 悉其相关寄存器的使用和配置, 说实话 128 单片机的难点就在如何配置寄存器, 寄存器太多, 太繁琐。但这也是它的精妙之处,经常使用某一个模块,就会很熟悉的,到时候又会觉得它 很方便了。 ? 概述:这个定时器是由一个 16 位的可编程的计数器(带有预分频功能)组成。这个定 时器用途很多, 它可以在对输入波形测量的同时产生输出波形, 脉冲宽度可以从毫秒级 到秒级之前改变。这个定时器包含 8 个输入捕捉/输出比较通道和一个脉冲累加器输入 捕捉功能可以用来检测跳沿信号并进行时间记录, 输出比较功能可以用来形成输出信号 和定时来产生软件延时。16 位的脉冲累加器可以用来做事件计数器和可控的累加器。 脉冲累加器在事件计数模式下共享定时器的通道 7。 对于所有寄存器的存取需要在一个 时钟周期里完成。 单独访问寄存器的高字节和低字节和对寄存器进行整字的访问结果可 能是不一样的。综上, TIM 模块有如下特点: 1.8 个输入捕捉/输出比较通道 2.可以对时钟进行预分频 3.16 位的计数器 4.16 位的脉冲累加器 操作模式: 停止模式:定时器关闭,因为此刻时钟被停止了。 冻结模式:只要控制器寄存器 TSCR1 中的冻结位 TSFRZ 没有被置 1,则定时器保持运 行。 等待模式:只要控制器寄存器 TSCR1 中的等待位 TSWAI 没有被置 1,则定时器保持运 行。 正常模式: 只要控制器寄存器 TSCR1 中的控制位 TEN 没有被清 0, 则定时器保持运行。? ? ? ? ?TIM 模块的结构框图如下: 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元从以上结构图上可以看出 TIM 模块总共有 8 个外部引脚: IOC0――IOC7 其中 IOC7 是输入 捕捉和输出比较的共享引脚,同时也可以被配置成脉冲累加器的输入引脚。 IOC6―― IOC0 是输入捕捉和输出比较的共享引脚。有 1 个定时器溢出中断, 8 个通道中断,1 个脉冲累加 器溢出中断和 1 个脉冲累加输入中断。 它可以由预分频器对总线时钟分频。 接下来我们就来 学习一下 TIM 模块的各个寄存器。 ? Timer Input Capture/Output Compare Select (TIOS) 定时器输入捕捉/输出比较选择寄存 器该寄存器共有 8 位分别对应 IOC0――IOC7 这 8 个通道, 通过配置该位来决定相应的通道是 作为输入捕捉使用还是作为输出比较使用。 (置 0――相应的通道被用作输入捕捉引脚 置 1――相应的通道被用作输出比较引脚) ? Timer Compare Force Register (CFORC) 定时器强制比较寄存器 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元向该寄存器的任何一位写 1 时会导致相应通道发生强制输出比较,这和正常情况下它的 TC 通道上发生输出比较效果一样,唯一不同的是强制输出比较时中断标志位没有置 1。 ? Output Compare 7 Mask Register (OC7M) 输出比较 7 掩码寄存器置位该寄存后相应通道 7 事件发生后, 其通道数据寄存器中的数值会被传输到相应的定时器 通道端口。通道 7 事件包括定时器的溢出和定时器通道的输出成功发生了比较。 OC7M[7:0]:置0――事件 7 发生后,输出比较 7 数据寄存器中的值不会被传输到定时器各 通道的相应端口。 置 1――事件 7 发生后,输出比较 7 数据寄存器中的值会被传输到定时器各通 道的相应端口。 ? Output Compare 7 Data Register (OC7D) 输出比较 7 数据寄存器这个寄存器就是和上面那个输出比较 7 掩码寄存器配合使用的, 该寄存器中可以存放相应的 数值,如果 OC7M 寄存器置位,一旦通道 7 事件发生(这个事件可以是定时器的溢出,或 者是通道 7 上成功发生了一次输出比较),输出比较 7 数据寄存器 OC7D 中的值就会被传输 到定时器端口数据寄存器中。 ? Timer Count Register (TCNT) 定时器计数寄存器这是 16 位主定时器的加计数器, 最好是对它进行 16 位的字访问, 如果分成高低字节访问得 出的结果是不一样的。注意:该寄存器在任何时刻可以被读取,正常情况下写该寄存器是无 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 效的。 ? Timer System Control Register 1 (TSCR1) 1 定时器系统控制寄存器?TEN:定时器使能位,置 0――关闭主定时器,包括计数器,这样可以用来减小功耗。置 1――允许定时器正常工作 ? TSWAI:等待模式下定时器模块停止位,置 0――等待模式下,定时器继续工作。 置 1――当单片机进入等待模式后关闭定时器模块,定时器中断不能够用来让 CPU 退出等 待模式,该位对脉冲累加器也会有影响。 ? TSFRZ :冻结模式下定时器模块停止位,置 0――冻结模式下,定时器继续工作。 置 1――当单片机进入冻结模式后关闭定时器计数器,这对仿真非常有用。该位不能够停止 脉冲累加器。 ? TFFCA :定时器快速清除所有标志位,置 0――定时器各标志寄存器的标志位采用正常 方式清除。 置 1――每读一次输入捕捉通道或者每写一次输出比较通道,标志寄存器 TFLG1 中的通道标志位 CnF 将会被清除。 对于标志寄存器 TFLG2,每一次对脉冲累计控 制寄存器 PACNT 的访问都会清除标志寄存器 PAFLG 中的 PAOVF 位和 PAIF 位。这 可以有效的节省软件开支,即在中断服务程序中无需添加额外的清中断标志位的指令, ? ? 但是要避免意外操作造成标志位的误清除。 PRNT :精准定时器控制位,置 0――不启动精准定时器,使用主定时器。置 1――启 用精准定时器,此时 PTPSR 寄存器中的所有位被用来对精准定时器进行预分频。 Timer System Control Register 2 (TSCR2) 定时器系统控制寄存器 2? ?TOI:定时器溢出中断使能位,置 0――禁止溢出中断发生 置 1――允许定时器溢出 时发生中断。 TCRE :定时器计数器复位使能位,置 0――当输出比较 7 事件发生一次成的输出比较 时计数器不复位。 置 1――当输出比较 7 事件发生一次成的输出比较时计数器发生 复位。 (其实我个人觉得没必要用它,除非特别需要,所以一般情况下将它清 0 即可) PR[2:0] :定时器预分频选择位,这 3 位用来设置对总线时钟的分频,分频系数如下表:? 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元由上表可知:通过设置最高可以对总线时钟进行 128 分频。至于选择多少分频,我们自己可 以配置。?Timer Toggle On Overflow Register 1 (TTOV)定时器通道溢出翻转寄存器只有在输出比较模式下, 该寄存器的设置才会生效, 当置 1 时它会优先于强制输出比较但是 并不优先于通道 7 事件。 置 0――禁止通道输比较的溢出翻转功能 置 1――使能通道输出 比较的溢出翻转功能。 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元?Timer Control Register 1/Timer Control Register 2 (TCTL1/TCTL2)1、2 定时器控制寄存 器这两个寄存器用来控制定时器输出比较模式下, 输出比较后相应通道输出高低电平值, 通过 如下的组合来实现,但是寄存器 OC7M 和寄存器 OCPDx 必须要被清除。由这幅表可知:当 OMx 和 OLx 分别置 0 时,定时器输出信号上不会发生比较。置 01 时, 相应的 OC 通道电平值发生翻转,置 10 时 OC 通道电平值输出低电平,置 11 时 OC 通道电 平值输出高电平。 ? Timer Interrupt Enable Register (TIE) 定时器中断使能寄存器这个寄存是用来控制每个输入捕捉和输出比较通道发生动作是是否引发硬件中断, 置 0―― 禁止标志寄存器 TFLG1 中相应通道的标志位引发硬件中断。 置 1――使能标志寄存器 TFLG1 中相应通道的标志位引发硬件中断。 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元?Timer Control Register 3/Timer Control Register 4 (TCTL3 and TCTL4) 3、4 定时器控制 寄存器这两个寄存器用来组合配置定时器输入捕捉模式下, 对需要捕捉的边沿信号的控制。 配置方 式如下表:由这幅表可知,当 EDGnB 和 EDGnA 置 00 时,禁止捕捉功能,置 01 时只捕捉上升沿信号, 置 10 时只捕捉下降沿信号,置 11 时捕捉任意跳沿信号(包括上升沿和下降沿) 。?Main Timer Interrupt Flag 1 (TFLG1)主定时器中断标志位 1?C[7:0]F :每当输入捕捉或者输出比较事件发生时相应通道的中断标志位会设置,用来 引发中断。通过写 1 来清除该标志位,写 0 是无效的。 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 ? Main Timer Interrupt Flag 2 (TFLG2) 主定时器中断标志位 2? ?TOF :当 16 位计数器从 0xFFFF 到 0x0000 时会发生溢出,此时该标志位置位,用来 引发定时器的溢出中断。需要向该位写 1 才能清除该位,写 0 是无效的。 Timer Input Capture/Output Compare Registers High and Low 0C7(TCxH and TCxL)定时 器输入捕捉/输出比较寄存器的高位字节和地位字节这个寄存器用来锁存相应通道计数器的当前值, 其值可以在任何时刻被读取。 在对该寄存器 进行写操作时需要注意, 只有在输出比较模式下可以任意时刻写入, 输入捕捉模式下写该寄 存器无效且无意义。 对该寄存器进行读写操作时, 如果分高低字节访问时必须先访问高字节, 再访问低字节。 说明:因为脉冲累加计数功能和精确定时器不常用,其相关寄存器我就省略不介绍了,其实 用法和学习方法都是类似的,如果需要用大家可以参考它的手册。此处与 TIM 定时模块相 关的寄存器我已介绍完毕。接下来我们就分别来测试一下的输出比较和输入捕捉功能。 ? 通道 0 的输出比较功能测试源代码(基于 128 单片机) /*这段程序是对 TIM 模块通道 0 输出比较功能的测试,采用的是中断的方式,采用 3 只不 同颜色的发光二极管来 作程序指示,1 只指示主程序,1 只指示是否进入了中断,1 只做 TIM 通道输出电平的指示, 此处我选择的是 通道 0 */ #include &hidef.h& #include &derivative.h& 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 #define #define #define #define #define LED_1 PORTB_PB0 //定义指示灯 1 控制端口为 B0 口LED_2 PORTB_PB1 //定义指示灯 2 控制端口为 B1 口 uchar unsigned char //宏替换 uint unsigned int time 500/*----------------------------------子函数申明----------------------------------------------*/ void delay(uint a); void light_1(); void light_2(); void Port_initail(); void TIM_initial(); //延时函数 //指示灯 1 函数 //指示灯 2 函数 //端口初始化 //TIM 模块初始化/*----------------------------------主程序--------------------------------------------------*/ void main(void) { Port_initail(); TIM_initial(); EnableI while(1) { TIE_C0I=0; light_1(); TIE_C0I=1; } //关闭通道的中断功能 //点亮指示灯 1 //打开通道的中断功能 //端口初始化 //TIM 模块初始化}/*----------------------------------- 功能子函数---------------------------------------------*/ void delay(uint a) // 延时函数 { uint i,j; for(i=0;i&a;i++) for(j=0;j&a;j++) ; }void light_1()//指示灯 1 函数 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元{ uchar cycle=3; while(cycle--) { LED_1=1; delay(time+200); LED_1=0; delay(time+200); } }void light_2() { uchar cycle=3; while(cycle--) { LED_2=1; delay(time); LED_2=0; delay(time); } }//指示灯 2 函数void Port_initail() { DDRB=0x03; } void TIM_initial() {//端口初始化函数// 定义 B0-B1 口为输出//TIM 模块初始化TIOS_IOS0=1; TSCR2_PR=4; TCTL1=0x00; TCTL2=0x01; TIE_C0I=1;//通道 0 作为输出比较 // 定时器时钟对总线时钟 16 分频=16MHz/16=1MHz //断开通道 4-7 的引脚端口,不做输出比较 //设置通道在输出比较发生后输出翻转电平 //打开通道的中断功能 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 TFLG1=0 //清各通道的中断标志位TFLG2=0 //清主定时器的溢出中断标志位 TC0=0 //设置通道 0 的计数比较值,当计数器计数到该值时发生比较输出 TSCR1_TEN=1; //打开 TIM 模块,开启定时器 }/*-------------------------------定时器通道 0 输出比较中断服务程序-----------------------------*/ #pragma CODE_SEG __NEAR_SEG NON_BANKED void interrupt 8 Timer_0 () { LED_1=0; //关闭指示灯 1 light_2(); //点亮指示灯 2 TFLG1_C0F=1; //清通道 0 的中断标志位 } 注意: 大家注意我在主程序里加了一条打开和关闭通道中断的语句, 大家在自己测试的时候 可以尝试把那两条语句去掉试试看,你会发现程序在不停的执行中断服务程序,原因就是 16 位的定时器溢出周期很短,如果不屏蔽它的中断的话它程序就会不停得进入中断,此时 主程序中的指令几乎得不到执行了, 这也就是有时候我们用中断不注意会造成程序死在中断 里的原因, 因此我们可以采取在主程序里关闭非必要的中断等主程序执行完再打开或者不用 中断法改用查询法或者设置看门狗来监控程序的运行。 这个就是我个人在实践中得出的一些 小经验。 ? 我们再用查询法来使用定时器的溢出标志位, 源代码如下, 大家可以仔细比较一下和中 断法的区别 /*这段程序是对 TIM 模块通道 0 输出比较功能的测试,采用的是查询的方式,采用 3 只不 同颜色的发光二极管来 作程序指示,1 只指示主程序,1 只指示是否进入了中断,1 只做 TIM 通道输出电平的指示, 此处我选择的是 通道 0 */ #include &hidef.h& #include &derivative.h& #define #define #define #define #define LED_1 PORTB_PB0 //定义指示灯 1 控制端口为 B0 口 LED_2 PORTB_PB1 //定义指示灯 2 控制端口为 B1 口 uchar unsigned char //宏替换 uint time unsigned int 500/*----------------------------------子函数申明----------------------------------------------*/ void delay(uint a); //延时函数 void light_1(); //指示灯 1 函数 void light_2(); //指示灯 2 函数 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 void Port_initail(); void TIM_initial(); //端口初始化 //TIM 模块初始化/*----------------------------------主程序--------------------------------------------------*/ void main(void) { Port_initail(); TIM_initial(); EnableI while(1) { light_1(); //点亮指示灯 1 if(TFLG1_C0F==1) // 判断是否发生了输出比较 { light_2(); } } //点亮指示灯 2 TFLG1_C0F=1; //清通道 0 中断标志位 //端口初始化 //TIM 模块初始化}/*----------------------------------- 功能子函数---------------------------------------------*/ void delay(uint a) // 延时函数 { uint i,j; for(i=0;i&a;i++) for(j=0;j&a;j++) ; }void light_1() { uchar cycle=3; while(cycle--)//指示灯 1 函数 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元{ LED_1=1; delay(time+200); LED_1=0; delay(time+200); } }void light_2() { uchar cycle=3; while(cycle--) { LED_2=1; delay(time); LED_2=0; delay(time); } }//指示灯 2 函数void Port_initail() { DDRB=0x03; } void TIM_initial() {//端口初始化函数// 定义 B0-B1 口为输出//TIM 模块初始化TIOS_IOS0=1; TSCR2_PR=4; TCTL1=0x00; TCTL2=0x01; TFLG1=0 TFLG2=0 TC0=0 TSCR1_TEN=1;//通道 0 作为输出比较 // 定时器时钟对总线时钟 16 分频=16MHz/16=1MHz //断开通道 4-7 的引脚端口,不做输出比较 //设置通道在输出比较发生后输出翻转电平 //清各通道的中断标志位 //清主定时器的溢出中断标志位 //设置通道 0 的计数比较值,当计数器计数到该值时发生比较输出 //打开 TIM 模块,开启定时器 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 } ? TIM 模块输入捕捉功能测试源代码(基于 128 单片机)/*这段程序是对 TIM 模块通道 0 输入捕捉功能的测试,采用的是中断的方式,采用 2 只不 同颜色的发光二极管来 作程序指示,1 只指示主程序,1 只指示是否进入了中断,此处我选择的是通道 0 来检测边 沿信号从而捕捉并 引发中断,大家可以用按键来产生触发信号,如果没有按键电路那就直接利用前面学过的 PWM 波来产生脉冲信号 的跳沿。 */ #include &hidef.h& #include &derivative.h& #define LED_1 PORTB_PB0 #define LED_2 PORTB_PB1 #define #define #define uchar unsigned char uint unsigned int time 500 //定义指示灯 1 控制端口为 B0 口 //定义指示灯 2 控制端口为 B1 口//宏替换/*----------------------------------子函数申明----------------------------------------------*/ void delay(uint a); //延时函数 void light_1(); void light_2(); void Port_initail(); void TIM_initial(); void PWM_initial(); //指示灯 1 函数 //指示灯 2 函数 //端口初始化 //TIM 模块初始化 //PWM 初始化/*----------------------------------主程序--------------------------------------------------*/ void main(void) { PWM_initial(); Port_initail(); TIM_initial(); EnableI while(1) { TIE_C0I=0; light_1(); TIE_C0I=1; } //打开通道的中断功能 //点亮指示灯 1 //打开通道的中断功能 //PWM 初始化 //端口初始化 //TIM 模块初始化 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元}/*----------------------------------- 功能子函数---------------------------------------------*/ void delay(uint a) // 延时函数 { uint i,j; for(i=0;i&a;i++) for(j=0;j&a;j++) ; }void light_1() { uchar cycle=3; while(cycle--) {//指示灯 1 函数LED_1=1; delay(time+200); LED_1=0; delay(time+200); } }void light_2() { uchar cycle=3; while(cycle--) { LED_2=1; delay(time); LED_2=0; delay(time); } }//指示灯 2 函数 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元void Port_initail() { DDRB=0x03; } void TIM_initial() {//端口初始化函数// 定义 B0-B1 口为输出//TIM 模块初始化TIOS_IOS0=0; TSCR2_PR=4; TCTL3=0x00; TCTL4=0x01; TIE_C0I=1; TFLG1=0 TFLG2=0 TSCR1_TEN=1; }//通道 0 作为输入捕捉 // 定时器时钟对总线时钟 16 分频=16MHz/16=1MHz //断开通道 4-7 的引脚端口,不做输入捕捉 //设置通道 0 捕捉上升沿 //打开通道的中断功能 //清各通道的中断标志位 //清主定时器的溢出中断标志位 //打开 TIM 模块,开启定时器/*-------------------------------定时器通道 0 输出比较中断服务程序-----------------------------*/ #pragma CODE_SEG __NEAR_SEG NON_BANKED void interrupt 8 Timer_0 () { LED_1=0; //关闭指示灯 1 light_2(); //点亮指示灯 2 TFLG1_C0F=1; //清通道 0 的中断标志位 }/*------------------------------PWM 模块初始化-------------------------------------*/ void PWM_initial() { PWMPOL_PPOL0=1; PWMCLK_PCLK0=1; PWMPRCLK=0x04; PWMCAE_CAE0=1; PWMSCLA=200; PWMPER0=200; // 通道 0 极性起始选择高电平 //通道 0 选择 SA 作为时钟源 // 时钟 A 的频率为总线时钟 16 分频获,clock_A=16/16=1MHz //通道 0 波形中央对齐 //clock_SA=1MHz/(2*200)=2.5kHz 通道周期 =0.4ms //通道 0 的 PWM 周期=0.4*2*200=160ms //PWM 初始化 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 PWMDTY0=100; PWME_PWME0=1; } ? 综上所述,我们对于 TIM 模块的配置使用可以分为如下几步: 1.配置相应通道是作为输入捕捉使用还是作为输出比较使用。 2.对定时器的时钟配置,选择对总线时钟的分频系数。 3.配置与输入捕捉相关的控制寄存器和输出比较相关的控制寄存器。 4.清除相应的通道的中断标志位,并选择是否允许相应通道的中断。 5.打开 TIM 模块,允许通道输出。 //通道 0 的占空比 =PWMDTY0/PWMPER0=50% // 打开 PWM 通道 0第五章第五章:Analog-to-Digital Converter (模 拟量转数字量模块)无论是在实际的工业控制过程还是一些嵌入式系统的设计过程中都经常会涉及到对模拟量 的处理,比如工业过程的几大物理量:温度、压力、流量、物位、液位等都几乎是模拟量的, 所以在送入微机处理之前需要将这些模拟量转换成数字量才行, 这就需要模数转换了, 有些 51 系列的单片机内部没有集成 ADC 模块,需要外接芯片才可以。经常我们常用的有 ADC0809、ADC0804、ADC0832 等。当然我们熟悉的一些 PLC 有专用的模拟量模块使用, 例如西门子 S7-300 有相应型号的 AI/AO 模块使用,那就另当别论了。此处我们针对单片机 这样的控制器,128 单片机内部集成有 ADC 模块,我们只要对其相关寄存器配置一下就可 以使用了。接下来我们就来熟悉一下 ADC 模块寄存器的配置,因为同样 ADC 模块寄存器 有很多,有很多其他功能和使用方法,我们仅学习一下其最主要的几个寄存器,其他功能在 掌握了这几个基本的寄存器后再去参考技术手册使用也并不难,因为对寄存器的介绍太繁 琐,相信我懒得写,大家看了也繁琐,那么我们就言简意赅一点。熟悉一下之后,自己动手 编程测试一下很容易掌握的。 概述:ADC12B16C 模块是一个有着高达 12 位分辨率、16 个通道并且可以多路选择的逐次 逼近型的模拟量转数字量的转换器。其拥有的特点如下: ? ? ? ? ? ? ? ? ? ? 有着 8 位、10 位、12 位可选的分辨率。 转换进入停止模式后由使用内部形成的时钟信号 每一次转换序列结束后自动返回到低功耗 可以软件设置比较值,并由转换器自动比较并发出中断 采样时间可以编程设置 转换结果可以选择左对齐或者右对齐 可以由外部触发来控制 转换序列完成后可以发出中断 可以 16 路的模拟量输入 可以有 1―16 位的序列转换长度 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 ? ? ? 拥有多通道的扫描和持续转换功能 可以由 4 路外部触发来控制 AD 转换 在多通道转换模式下可以选择通道编程来选择回绕的通道关键寄存器学习: ? ATD Control Register 0 (ATDCTL0)ATD 控制寄存器 0由图可知位 7 是保留位,位 4――位 6 是无效位 ? WRAP[3-0] : 回绕通道选择位, 这几位是在多通道转换模式下进行回绕通道的选择配置, 其配置方法如下:通过这四位配置后在多通道转换模式下转换结束后将从该通道回绕到模拟量通道 0, 如果不 选择多通道转换模式,我们只需要将这几位置 0 即可,其实默认状态下该寄存器也是置 0, 不用时不配置也是可以的。 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 ? ATD Control Register 1 (ATDCTL1) ATD 控制寄存器 1? ?ETRIGSEL:外部触发源选择,这一位和后面的 ETRIGCH[3:0]位联合使用,通过置 1, 并且由 ETRIGCH[3:0]位来选择外部触发源。 SRES[1:0] :AD 转换分辨率选择位,这两位来选择 AD 转换的分辨率,配置方法如下:由表可知默认状态下是 8 位的分辨率, 分辨率越高可以提高转换精度, 但是会增长了转换时 间,举个例子,如果我们需要对 5V 的 DC(直流)电压进行采样的话,如果是 8 位的分辨 率,则: div=5/28 =19.53mv,如果是 10 的分辨率,则:div=5/210 =4.88mv,如果是 12 位的 分辨率,则:div=5/212 =1.22mv。至于选择多少位的分辨率可以参照以上表格设置。 ? SMP_DIS:内部采样电容前放电位,置 0――采样之前采用电容不放电 置 1――采 样相应通道前内部采用电容放电,这样会增加 2 个 ATD 时钟周期。 ? ETRIGCH[3:0]:外部触发通道选择位,通过配置这 4 位来选择其中任何一个通道或者 外部 4 个中的任何一个触发输入做触发源。配置表格如下: 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 ? ATD Control Register 2 (ATDCTL2) ATD 控制寄存器 2?AFFC:ATD 快速清除所有标志位,置 0――通过向 CCF[n] 位写 1 来清除相应的标志 位 置 1――快速清除标志位,无论转换结果比较位 CMPE[n] 是否使能,每一次读取 结果寄存器都会自动清除相应的 CCF[n] 标志位。 ICLKSTP :停止模式下的内部时钟位,置 0――如果 AD 转换正在进行,如果进入停止 模式,AD 转换会中止,当退出停止模式后 AD 转换自动重启。 置 1――进入停止模 式后 AD 转换通过使用内部时钟而继续。 ETRIGLE :外部触发电压及信号跳沿控制位 ETRIGP :外部触发极性选择位?? ?由上表格可知道通过配置 ETRIGLE 和 ETRIGP 位来选择外部的触发方式,可以有高电平触 发、低电平触发、上升沿触发和下降沿触发四种方式选择。 ? ETRIGE :外部触发模式使能位,置 0――禁止外部触发 置 1――使能外部触发 ? ? ASCIE :转换序列完成中断使能位,置 0――禁止转换序列完成后的中断请求 置 1― ―当 SCF=1 时每当转换序列完成,都会引发中断请求。 ACMPIE: ATD 比较中断使能位,当比较寄存器 ATDCMPE 中的比较位被使能后,这 一位用来使能比较中断。 置 0――屏蔽掉比较中断请求 当 CCF 标志位置 1 都会发出比较中断请求。 ? ATD Control Register 3 (ATDCTL3) 置 1――当比较功能使能后每ATD 控制寄存器 3?DJM :转换结果数据对齐选择位,因为转换结果都是无符号数,我们可以通过此位来选 择其在结果寄存器的对齐方式。 置 0――转换结果左对齐 置 1――转换结果右对齐 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 ? S8C, S4C,S2C, S1C:转换序列的长度选择位,这几位用来设置每个序列的转换次数。 在单片机复位的时候 S4C 位被默认得置 1 即每个序列默认转换 4 次。当然我们可以自 己选择转换次数,如下表:?FIFO :结果寄存器 FIFO 模式位,当该位置 0 的时候,转换结果按照转换序列次序放在 转换结果寄存器中,第一转换结果放在 ATDDR0 中,第二次结果放在 ATDDR1,第三 次结果放在 ATDDR2,依次类推。当该位置 1 的时候,由 ATDSTAT0 中的 CC3-0 位决 定结果的存放。 置 0――由转换序列的长度决定转换结果在相应结果寄存器中的存 放。 置 1――转换结果放置在连续的结果寄存器中。?FRZ[1:0]: 背景调试冻结使能位,当在调试模式下,当碰到断点的时候 AD 转换会暂停, 由这两位的设置 AD 转换将会做出什么反应,如下:这两位置 00 时继续转换,置 01 是系统预留(一般不用) ,置 10 完成当前转换,然后冻结, 置 11 立即冻结。 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 ? ATD Control Register 4 (ATDCTL4) ATD 控制寄存器 4?SMP[2:0]:采样时间选择位,由这三位选择 AD 转换时钟周期中采样时间的长度,配置 如下表:?PRS[4:0] :ATD 时钟预分频,由这 5 位对总线时钟分频得到 AD 转换时钟,频率计算公 式如下:f ATDCLK =? ATD Control Register 5 (ATDCTL5)f BUS 2 × ( PRS + 1)ATD 控制寄存器 5?SC:特殊通道转换位,该位有效后将会由 CD,CC, CB and CA 位来决定特殊通道开始转 换。置 0――禁用特殊通道转换 置 1――使能特殊通道转换 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 ? SCAN :连续序列转换模式位,该位决定相应通道是进行序列循环连续转换还是只转换 一次,如果外部触发位 ETRIGE=1 ,则设置改位是无效的,换言之,外部触发转换总是 启动序列转换一次。 置 0――序列转换只进行一次 置 1――序列持续转换(扫描 模式) ? MULT:多通道采样模式,当该位置 0 时,采样单个通道,由 CD/CC/CB/CA 决定选择 哪路。当该位置 1 时,多通道采样,采样通道的数量由 S8C, S4C, S2C,S1C 决定。第一 个采用通道仍由 CD/CC/CB/CA 决定,随后的采样通道再逐个递增。 置 0――采样单 个通道 置 1――多通道逐个采样 CD, CC,CB, CA :模拟量输入通道选择位,单通道转换模式下由这几位指定待转换的通 道,多通道转换模式下由这几位决定起始转换通道,随后再逐个递增采样。如下:? 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 ? ATD Status Register 0 (ATDSTAT0) ATD 状态寄存器 0?SCF : 序列转换完成标志位, 每当一个序列转换完成, 如果序列是持续转换模式 SCAN=1 时,每一次转换完成都将被转换完成。发生如下情况会清除该标志位: 1.向 SCF 写 12.写 ATDCTL5,即启动一次新的序列转换 3.如果 AFFC=1,每次访问结果寄存器都将清除该标志位 置 0――转换序列未完成 置 1――转换序列已完成 ? ETORF: 外部触发侵占标志位,在边沿检测模式即 ETRIGLE=0 时,当序列正在转换时, 如果有效的边沿触发信号被检测到将会置位该位,这一位可以通过以下几种情况清除: 1.向 ETORF 写 12.写寄存器 ATDCTL0,1,2,3,4, ATDCMPE 和 ATDCMPHT(转换序列被中止) 3.写寄存器 ATDCTL5(一个新的转换序列被启动) 置 0――没有发生外部边沿触发信号的侵占 置 1――发生了外部边沿触发信号的侵占 ? FIFOR:结果寄存器侵占标志位,这一位表明了相应的结果寄存器在其序列完成标志之 前是否已经被写入了转换结果,以下情况发生会清除该位: 1.向 FIFOR 写 12.写寄存器 ATDCTL0,1,2,3,4, ATDCMPE 和 ATDCMPHT (转换序列被中止) 3.写寄存器 ATDCTL5(一个新的转换序列被启动) 置 0――结果寄存器没有被侵占写入 置 1――结果寄存器被侵占写入了转换结果 ? CC[3:0] :转换计数器,这 4 位二进制数组成了转换计数器,由转换计数器指明了当前 转换结果的存放位置,例如: CC3=0, CC2=1,CC1=1, CC0=0 表明当前的转换结果被放 在了结果寄存器 6 当中。FIFO=0 时,该计数器初始化时被设置为 0,FIFO=1 时,该计 数器并没被初始化, 转换计数器计数到最大值后会回绕到初始值, 并且此时中止转换或 者启动一个新的转换序列都会清除该转换计数器。 ATD Conversion Result Registers (ATDDRn) ATD 转换结果寄存器?这是一个 16 位的寄存器,其中存放着一个转换序列中对应的转换结果,说到转换序列,意 思就是一个转换序列中可以包含 N 次转换,转换次数 N 由序列长度决定,每一次的转换结 果对应得存放到 ATDDRn 中,例如如果序列长度为 4,那么发生一次序列转换就会有对应 的 4 个转换结果依次存放到 ATDDR0 到 ATDDR3 中。转换结果都是以无符号数存放的,存 放位置由数据对齐方式选择,分为左对齐和右对齐两种情况如下: 1.Left Justi fied Result Data (DJM=0) 数据左对齐2. Right Justified Result Data (DJM=1)数据右对齐 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元?转换结果的存放位置和转换分辨率也有如下的关系:由表格可知:当采用 8 位分辨率、数据左对齐时,结果寄存器的 4― 11 位存放转换结果; 当采用 8 位分辨率、数据右对齐时,结果寄存器的 0―7 位存放转换结果;当采用 10 位分辨 率、数据左对齐时,结果寄存器的 2―11 位存放转换结果;当采用 10 位分辨率、数据右对 齐时, 结果寄存器的 0―9 位存放转换结果; 当采用 12 位分辨率时不论数据右对齐还是左对 齐结果寄存器的 0―11 位存放转换结果。 因此读取转换结果时按这个规则读取才可获得正常 值。 ? 到此为止,AD 模块的基本用法和相关寄存器已经结束完毕,至于它剩下的几个比较寄 存器和中断寄存器在熟悉了基本用法后很容易通过查看技术手册掌握,此处不再多说 了, 说多了也繁琐。 接下来我们就来通过编程测试一下这个 AD 模块。 使用的步骤如下: 1.设定 AD 转换的分辨率(选择 8 位/10 位/12 位) 2.设定 AD 转换的时钟周期和采样时间 3.设定每个转换序列的长度 4.选择转换通道,启动转换 5.读取相关状态寄存器的相关序列完成标志位,查看是否转换完成 6.读取转换结果 ? 我们以一个 5V 直流电源串接一个 10K 的电位器,由电位器中间抽头取电压值进行 AD 转换,测试源代码如下:/*--------------------------------AD 转换测试程序------------------------------*/ /*------------------------对 5V 的 DC 电压进行采样检测,调节电位器 -----------------*/ #include &hidef.h& #include &derivative.h& 基于飞思卡尔 MC9S12XS128MCU 的模块讲解及测试安徽工业大学 自动化系 刘昌元 #define #define #define #define LED_1 PORTB_PB0 //定义指示灯控制口LED_2 PORTB_PB1 uchar unsigned char //宏替换 uint unsigned int 200 // 延时宏替换#d/*----------------------------------- 子函数声明-------------------------------*/ void delay(uint a); // 延时函数 //指示灯 1 //指示灯 2 //AD 模块初始化void light_1(); void light_2(); void AD_initial();void AD_start(uchar channel); //设置 AD 通道号,启动 AD 转换 void Port_initial(); //端口初始化 /*-------------------------------------主程序---------------------------------*/ void main(void) { Port_in

我要回帖

更多关于 单片机 的文章

 

随机推荐