首页 理论教育 MSP430单片机入门与提高

MSP430单片机入门与提高

时间:2023-12-05 理论教育 版权反馈
【摘要】:3MSP430单片机通用I/O端口I/O端口是单片机控制系统对外沟通的最基本部件,从基本的键盘、LED显示到复杂的外设芯片等,都是通过I/O端口的输入、输出操作来进行读取或控制的。在MSP430系列中,不同单片机拥有的I/O端口数目不同,引脚最少的MSP430F20××只有10个可用的I/O端口,而功能更丰富的MSP430FG46xx拥有多达80个I/O端口。MSP430F249单片机的I/O端口主要有以下特征。

MSP430单片机入门与提高

3 MSP430单片机通用I/O端口

I/O端口是单片机控制系统对外沟通的最基本部件,从基本的键盘、LED显示到复杂的外设芯片等,都是通过I/O端口的输入、输出操作来进行读取或控制的。为满足单片机系统对外部设备控制的需要,MSP430提供了许多功能强大、使用方便灵活的输入/输出端口。一般来说,MSP430单片机的I/O端口可分为以下几种:

(1)通用数字I/O端口,用于外部电路数字逻辑信号的输入和输出。

(2)并行总线输入/输出端口,用于外部扩展需要并行接口存储器等芯片。一般包括数据总线、地址总线和包括读写控制信号的控制总线等。

(3)片内设备的输入/输出端口,如定时器/计数器的计数脉冲输入,外部中断源信号的输入,A/D输入、D/A输出,模拟比较输入端口,脉宽调制(PWM)输出端口等。有的单片机还将LCD液晶显示器的接口也集成到单片机中。

(4)串行通信接口,用于计算机之间或者计算机和通信接口芯片之间的数据交换,如异步串行接口(RS-232、RS-485)、I2C串行接口、SPI串行接口、USB串行接口等。

为了减少芯片引脚的数量以降低芯片的成本,又能提供更多功能的I/O端口,现在许多单片机都采用了I/O端口复用技术,即端口可作为通用的I/O端口使用,也可作为某个特殊功能的端口使用,用户可根据系统的实际需要来定义使用。这样就为设计开发提供了方便,简化了单片机系统的硬件设计工作。

在MSP430系列中,不同单片机拥有的I/O端口数目不同,引脚最少的MSP430F20××只有10个可用的I/O端口,而功能更丰富的MSP430FG46xx拥有多达80个I/O端口。MSP430F249单片机有6组I/O端口:P1~P6。每组I/O端口都有8个可以独立编程的引脚,例如P1端口有8个可编程引脚,为P1.0~P1.7。所有这些I/O端口都是双功能(有的为3功能)复用的。其中,第一功能均作为数字通用I/O端口使用,而复用功能则分别用于中断、时钟/计数器、USCI、比较器等应用。这些I/O端口同外围电路构成单片机系统的人机接口和数据通信接口。

MSP430F249单片机的I/O端口主要有以下特征。

(1)每个I/O端口可以独立编程设置。

(2)输入、输出功能可以任意结合使用。

(3)P1和P2端口具有中断功能,可以单独设置成上升沿或下降沿触发中断。

(4)有独立的输入/输出寄存器。

3.1 通用I/O端口

MSP430F249单片机的每组I/O端口都有4个控制寄存器,分别为方向控制寄存器Px DIR、输入寄存器PxIN、输出寄存器PxOUT和功能选择寄存器PxSEL,此处,小写字母“x”表示6组I/O端口的数字序号,x=1~6,即P1端口的方向控制寄存器为P1DIR,P6端口的方向控制寄存器为P6DIR。另外,P1和P2端口还具有3个中断寄存器,分别为中断允许寄存器PxIE、中断沿选择寄存器PxIES和中断标志寄存器PxIFG,此处,x=1~2。

1.方向控制寄存器PxDIR

该寄存器控制Px端口的各个引脚的方向。设置相应的比特(bit)位为1时,相对应的引脚为输出;设置相应的bit为0时,则对应的引脚为输入。Px DIR寄存器复位时初始值全部输入为0。Px DIR寄存器的比特分配如表3-1所示。

表3-1 PxDIR寄存器的比特分配

可以看出,Px端口的每个引脚都可以单独配置成输入或者输出方向的控制。需要注意的是:MSP430系列单片机端口输出电流最大为6 m A,当需要驱动比较大的负载的时候,要利用三极管缓冲器来提高端口的驱动能力。

MSP430单片机的I/O端口为双向I/O端口,因此在使用I/O端口前首先要用方向选择寄存器来设置每个I/O端口的方向,在程序运行中还可以动态改变I/O端口的方向。例如P1.0、P1.1、P1.2接有按键,P1.4、P1.5、P1.6接有LED,通用I/O端口应用示例如图3.1所示。

图3.1 通用I/O端口应用示例图

其中按键为输入设备,按键未闭合时,电阻R4、R5、R6将端口P1.0、P1.1、P1.2上拉到电平;按键闭合时,按键将对应的端口短路到地。P1.0、P1.1、P1.2要设置为输入,P1.4、P1.5、P1.6外接发光二极管,要设置为输出。程序如下:

其中,BIT0~BIT7为宏定义,P1DIR|=BIT4+BIT5+BIT6是将P1DIR寄存器的第4、5、6比特位置1,即配置为输出;P1DIR &=~(BIT0+BIT1+BIT2)是将P1DIR寄存器的第0、1、2比特位置0,即配置为输入。由于PxDIR寄存器在复位过程中会被清0,没有被设置的I/O端口方向均为输入状态,因此第二句可以被省略。对于所有已经设成输出状态的I/O端口,可以通过Px OUT寄存器设置其输出电平。

2.输入寄存器PxIN

在输入的模式下,读取该寄存器的相应比特来获得相应引脚上的数据。在输入模式下,当I/O端口相应输入高电平时,该寄存器相应的比特为1;当I/O端口相应输入低电平时,该寄存器相应的比特则为0。PxIN寄存器的比特分配如表3-2所示。

表3-2 PxIN寄存器的比特分配

该寄存器为只读寄存器,写无效。其每个比特可以单独读取,从而获得相应引脚上的输入数据或者引脚的状态。

3.输出寄存器Px OUT

在输出模式下,如果该寄存器的相应比特设置为1时,相应的引脚输出为高电平;如果设置该寄存器的相应比特为0时,则相应的引脚输出低电平。Px OUT寄存器的比特分配如表3-3所示。

表3-3 Px OUT寄存器的比特分配

值得注意的是:Px OUT复位时其值不确定,在使用过程中应该先使Px OUT的值确定以后才设置方向控制寄存器。

对于所有已经被设成输入状态的I/O端口,可以通过PxIN寄存器读回其输入电平。例如读回P1.0端口上所接按键的开关状态,若处于闭合状态(低电平),则从P1.4端口输出低电平点亮LED,程序如下:

if((P1IN &BIT0)==0)P1OUT|=BIT4; //P1.4输出低电平点亮LED

4.功能选择寄存器PxSEL

用于设置Px端口的每一个引脚作为一般I/O端口使用和作为外围模块的功能使用的情况。当该寄存器的相应比特设置为1时,其对应的引脚为外围模块的功能,即第二功能,具体每个端口的第二功能请参考芯片手册。当该寄存器的相应比特设置为0时,其对应的引脚为一般I/O端口。PxSEL寄存器的比特分配如表3-4所示。其复位值全为0,默认为I/O端口功能。

表3-4 PxSEL寄存器的比特分配

在MSP430F249单片机中,很多内部功能模块也需要和外界进行数据交换,为了不增加芯片引脚数量,大部分都是I/O端口复用引脚,导致MSP430F249单片机的所有I/O端口都具有第二功能。通过寄存器PxSEL可以设置某些I/O端口作为第二功能使用。例如从MSP430F249芯片手册中可以查到,MSP430F249系列单片机的P3.4、P3.5端口的第二功能为串行口的TXD、RXD。若需要将这两个引脚配置为串口收发引脚,则须将P3SEL的第4、5比特位置高,程序如下:

P3SEL|=BIT4+BIT5;//P3.4、P3.5设为串口收发引脚

5.中断允许寄存器PxIE

该寄存器控制P1、P2端口的中断允许。设置相应的比特为1,则对应的引脚允许中断功能;如果设置相应的比特为0,则对应的引脚不允许中断功能。寄存器的比特分配如表3-5所示。其复位值全为0,默认为不允许中断。

表3-5 PxIE寄存器的比特分配

6.中断沿选择寄存器PxIES

控制P1、P2端口的中断触发沿选择。如果设置相应的比特为1,则其对应的引脚选择下降沿触发中断方式;如果设置相应的比特为0,则其对应的引脚选择上升沿触发中断方式。PxIES寄存器的比特分配如表3-6所示。其复位值全为0,默认为上升沿触发中断。

表3-6 Px IES寄存器的比特分配

在使用I/O端口中断之前,需要先将I/O端口设置为输入状态,并允许该比特位的中断,再通过PxIES寄存器选择触发沿方式为上升沿触发或者下降沿触发。例如将P1.0、P1.1、P1.2端口设为外部中断源,P1.0端口设为上升沿触发,P1.1、P1.2端口设为下降沿触发,程序设计如下:

7.中断标志寄存器PxIFG

如果P1、P2端口相应的比特为1,则该位对应的引脚有外部中断产生;若相应的比特为0,则其对应的引脚没有外部中断产生。PxIFG寄存器的比特分配如表3-7所示。其复位值全为0,默认为未发生中断。

表3-7 PxIFG寄存器的比特分配

无论中断是否被允许,也无论是否正在执行中断程序,只要对应的I/O端口满足中断条件(如一个下降沿触发),PxIFG中的相应比特位都会立即置1并保持,必须通过软件复位将其清零,最大可能地保证不会漏掉每一次中断。在MSP430系列单片机中,P1端口的8个中断和P2端口的8个中断各公用了一个中断入口,当引脚中断功能打开后,外部输入的变化会使得PxIFG对应的比特位置1。当有多个引脚产生中断时,可以通过查询该寄存器在中断服务程序中用于判断哪一位I/O端口产生的中断。下面的中断服务程序示范P1.0、P1.1、P1.2端口发生中断后将P1.4、P1.5、P1.6端口的LED点亮。

以上点亮LED的程序为P1OUT=~BIT6,而没有用P1OUT &=~BIT6,原因是P1OUT &=~BIT6只会影响到P1.6,其他引脚状态不变。当三个按键都闭合后,三个LED都会被点亮,按键将对LED不起控制作用。

另外,在程序退出中断前一定要软件清除中断标志,程序中语句为P1IFG=0,否则由于该中断标志位保持为1,中断退出后又会引发另外一次相同的中断,中断就会不停发生。类似的原理,即使I/O端口没有出现中断条件,程序向PxIFG寄存器相应位写“1”,也会引发中断。更改中断沿选择寄存器中的位相当于产生了跳变,也会引发上升沿或者下降沿中断。所以更改PxIES寄存器应该在关闭中断后进行,并在打开中断之前及时清除中断标志,这种软件产生中断的方式称为软中断。

3.2 LED彩灯控制

I/O端口的应用主要包括三个方面:一般I/O端口、中断功能端口和外围模块特殊功能端口。从这一节开始,我们列举几个具体的应用实例。

LED是一种电路设计中常用的显示器件,比如很多电子设备中,当电源打开时采用LED作为电源指示,系统出现异常时采用LED闪烁提示报警。将发光二极管排列成方阵8×8或者16×16,构成一个点阵模块,再由这些模块可以构成工作和生活中常用的LED电子显示屏,显示单色或者彩色汉字及各种图形,如体育场馆中的大型显示屏。

实例3.1 彩灯控制

任务要求:利用MSP430F249单片机的P1端口控制8个发光二极管D1~D8,P1端口接入三个开关K1~K3,当K1闭合时,D1和D4闪烁,闪烁时间1 s;当K2闭合时,D2和D5闪烁,闪烁时间2 s;当K3闭合时,D1~D8循环闪烁,闪烁时间1 s。

分析说明:LED是一种半导体器件,当两端压降大于1 V时,通过5 m A左右的导通电流时即可发光。导通电流越大,亮度越高,但若电流过大,会烧毁二极管,一般控制在3~20 m A。在这里,给发光二极管串联一个电阻的目的就是为了限制通过发光二极管的电流不要太大,因此这个电阻又称为“限流电阻”,通常取300Ω~1000Ω。MSP430F249单片机的I/O端口输出电流最大为6 m A,所有电流之和不超过48 m A。且当其I/O端口输出“0”时,可以吸收最大40 m A的电流。因此,采用单片机I/O端口控制发光二极管负极的设计。

1)硬件电路设计

在桌面或者开始菜单中点击图标,打开Proteus开发环境,单击菜单File→New design,新建一个Default设计工程,保存文件为Flash.DSN,选择器件按钮单击P按钮,添加如表3-8所示的元件。

表3-8 实例3.1元件表

原理图编辑窗口中放置元件,以单片机为中心合理布局,尽量减少导线的交叉,导线过多的地方可用标号label表示连接关系,在对象选择器中选择Power和Ground放置电源和地线,按照设计要求连接好各元件之间的连线。双击各元件编辑参数,完成原理图设计。P1端口接8个LED,P2端口接三个开关。硬件电路如图3.2所示,限流电阻R1~R8取330Ω,开关上拉电阻取4.7 kΩ。

2)程序设计

图3.2 实例3.1彩灯控制硬件电路图

程序说明:程序首先包含了msp430f249.h头文件,该头文件中给出了该系列单片机内部寄存器名字的C语言的定义,比如P1DIR、P2OUT等,通过已定义的这些名字,以及利用C语言,可以直接对寄存器赋值或者读取寄存器的值,从而完成单片机功能的调用。

主程序中首先用WDTCTL=WDTPW+WDTHOLD语句关闭看门狗功能(看门狗具体内容请参考第5章),因为MSP430单片机复位后会默认启动看门狗,程序正常执行时应关闭该功能或者定时复位看门狗。

主循环中读取P2端口的输入值,判断是哪一个开关闭合,控制LED闪烁,其中delayus函数是通过软件实现延迟,需要注意的是P1端口的某一位输出为低电平时对应的LED点亮,因为LED的阳极接电源,而阴极接的是单片机的端口。在K3闭合时,通过mask每次累加得到P1端口的对应位,mask初始值为0x01,每次累加后变为0x02、0x04、0x08…,一直到0x100后恢复原来的值0x01,这一段代码也可以用mask<<=1左移运算来代替,左移运算的效率要比加法高,读者可以自行体会。

3)仿真结果与分析

点击桌面或者开始菜单中的IAR开发环境图标,单击File菜单的New→Workspace新建一个工作区,如图3.3所示。点击菜单Project→Create New Project新建工程,如图3.4所示。

图3.3 新建工作区

图3.4中有个Tool Chain:MSP430表示选择的芯片类型,另外在Project templates(工程模板)下,可以选择asm(汇编语言)、C++(C++语言)、C(C语言),这里可以选择C。展开C前面的“+”号,点击main之后再点OK按钮得到如图3.5所示的一个空白工程模板,保存工程名。根据需要选择工程保存的位置,更改工程名,这里工程名设置为Flash保存。

图3.4 新建工程

图3.5 工程模板

模板中已经存在一个main.c文件,将前述的代码加入到该文件中。如果还需要增加新的文件,可以通过File→New→File编写新的程序文件,保存后可通过Project →Add Files菜单将新的程序文件加入到工程中。

下一步是IAR的工程参数的设置和代码的编译。点击IAR菜单Project→Options,得到如图3.6所示的设置界面。

在General Options选型中,Device设置选择合适的单片机型号,这里我们选择与硬件原理图相对应的MSP430F249,其他都设置为默认即可。

为生成单片机运行所需的程序文件,选择Linker选型,得到设置界面如图3.7所示。

在Output file选项中,勾选Override default选项,输入文件名和类型,选择Other单选按钮,在Output选项中可以有很多种不同的输出格式选择。我们可以选择其中三种格式,一种是,即intel standard(intel公司标准),此时文件名应该为Flash.hex,这个输出格式可以供Proteus进行仿真,但是不能源码调试,或者作为单片机下载的二进制文件;一种是,即TI公司对MSP430系列单片机利用BSL方式进行烧写的一种格式,此时文件名应该为Flash.txt;还有一种是,这是Proteus对MSP430系列单片机实现源码级调试的文件格式,此时文件名应该为Flash.d90,为以后程序调试方便,可以选择最后一种。其他的输出文件格式就不一一介绍了。

图3.6 工程参数设置

图3.7 程序文件选择

最后代码的编译可以通过菜单Project→Make,或者用快捷键F7,或者单击工具栏图标,对整个工程进行编译,当程序没有错误时,在IAR软件输出窗口提示代码编译的结果,如图3.8所示。

图3.8 编译结果输出窗口

最后两行表示程序的错误和警告的数量,当有错误警告提示可以根据错误和警告提示修改代码,错误不消除将不能得到可运行的程序文件;警告要根据具体情况分析解决。作为初学者应该将程序中所有的错误和警告都予以排除,养成良好的编程风格和习惯。当程序编译通过后,将在工程目录的子目录\Debug\Exe下,生成所需的编程或者仿真用的文件。

双击Proteus原理图设计窗口中的MSP430F249单片机,如图3.9所示。

图3.9 编辑元件属性

在Program File中选择装载可执行文件Debug\Exe\Flash.d90,点击Proteus工程窗口左下角的第一个按钮运行仿真程序,点击K1可以观察到D1和D4灯亮0.1s灭0.1s;运行后点击K2,可以观察到D2和D5灯亮0.2 s灭0.2 s;运行后点击K3,可以观察到D1~D8周而复始逐个点亮。开关K1闭合时,仿真结果如图3.10所示。

图3.10 实例3.1仿真结果图

当程序运行不正常时,可以利用Proteus的debug菜单MSP430 source code进行源码调试,如图3.11所示。具体调试方法请参考附录。

图3.11 源码调试

4)注意问题

应用I/O端口输出时,在系统的软硬件设计上应注意的问题如下。

输出电平的转换和匹配。如一般MSP430系统的工作电源为3.3伏(手持系统往往采用1.5 V~3 V电源),所以I/O端口的输出电平为3.3 V。当连接的外围器件和电路采用5 V、9 V、12 V、15 V等与3.3 V不同的电源时,应考虑输出电平转换电路。

输出电流的驱动能力。MSP430的I/O端口输出可以提供4 m A左右的驱动电流。输出总电流最大为48 m A。当连接的外围器件和电路需要大电流驱动或有大电流灌入时,应考虑使用功率驱动电路。

输出电平转换的延时。MSP430是一款高速单片机,当系统时钟为8M时,执行一条指令的时间为0.125μs,这意味着将一个I/O引脚置“1”,再置“0”仅需要0.125μs,即输出一个脉宽为0.125μs高电平脉冲。在一些应用中,往往需要较长时间的高电平脉冲驱动,如步进电机的驱动,动态LED数码显示器的扫描驱动等,因此在软件设计中要考虑转换时间延时。对于不需要精确延时的应用,可采用软件延时的方法,编写软件延时的子程序。如果要求精确延时,要使用MSP430内部的定时器。

实例3.2 花样彩灯控制

任务要求:利用MSP430F249单片机的P1端口控制8个发光二极管D1~D8,点亮顺序如表3-9所示,每个发光二极管点亮时间为0.5 s。

表3-9 流水灯点亮次序(低电平为点亮)

分析说明:利用单片机的P1端口控制8个LED,其电路图与图3.2类似,但是此处不需要开关输入,重点在于C程序设计的算法和技巧。

1)硬件电路设计

在桌面或者开始菜单中点击图标,打开Proteus开发环境,单击菜单File→New design,新建一个default设计工程,保存文件为light2.DSN,选择器件按钮单击P按钮,添加MSP430F249、LED、RES等元件。在原理图编辑窗口中放置元件,硬件电路如图3.12所示。

图3.12 实例3.2花样彩灯控制硬件电路图

2)程序设计

程序说明:程序首先定义了一个枚举类型LED_MOD,定义了四种显示模式,分别是单个LED左移模式、单个LED右移模式、多个LED左移模式和多个LED右移模式,分别对应表3-9中的四种模式,利用枚举类型定义变量mode,该变量在程序中控制LED显示的方式。

主程序中首先运行WDTCTL=WDTPW+WDTHOLD,关闭看门狗功能,P1输出全部为高电平,关闭所有的LED。

主循环中利用for循环控制LED的顺序点亮,循环次数SHIFT_NUM为宏定义,这样的写法可以提高程序的可读性和可移植性。在for循环中首先是单个LED左移模式,mask为P1输出口的值,起始值为0x01,后面一条语句P1OUT=~mask,将mask取反赋值给P1端口,P1端口输出0x FE,使得P1.0对应的LED点亮,其他LED熄灭,mask<<=1语句使得每次循环时mask左移一次,即mask值从0x01→0x02→0x04→0x08→0x10……0x80,再左移一次mask变为0x100,注意mask定义为uint,为16位整数,不会因为8次移位后变为0,这时显示模式应该转换为单个LED右移模式,初始值为0x80,mask再逐次右移,即0x80→0x40→……0x01;当mask右移8次后为0时,显示模式转换为多个LED左移模式,初始值0x01,在循环中mask<<=1;mask|=1两条语句使得mask的值0x01→0x03→0x07→…0x1FF,即LED从左到右依次多个点亮,当移位8次mask的值将变为0x1FF,转换为多个LED左移模式,初始值为0x7F,只有P1.7端口LED的熄灭,在循环中mask>>=1;mask &=~0x80语句使得mask的值从0x7F→0x3F→0x1F……0x00,LED从右到左依次多个熄灭,最后重新从单个LED左移模式开始,如此反复。模式变换的语句为mode++;mode%=4,模式初始值按照枚举的定义为0,每次模式变换后加1,mode%=4 为mode对4取余,即mode值为0、1、2、3时,mode%=4的值依旧是0、1、2、3,当mode加1等于4,再取余时mode的值重新为0。如此实现了模式的循环变换,当然这种写法并不是唯一的,也可以采用以下代码:if(++mode==4)mode=0。读者注意体会其中的不同之处。

3)仿真结果与分析

程序的仿真运行,点击运行后可以观察到LED逐渐变换的效果。多个LED左移模式,仿真结果如图3.13所示。

图3.13 实例3.2花样彩灯控制仿真结果图

4)注意问题

本实例采用了多个模式变换来实现流水灯的控制,程序中利用了枚举变量,并采用switch语句控制模式的循环,要特别注意模式切换时mask的初始值的取值。

以上的两个实例分别介绍了按键控制的闪烁灯和多种模式变换的流水灯,下面一个实例为利用按键选择LED显示方式更为复杂的花样灯设计,一方面理解单片机I/O端口的输入和输出控制,一方面更深入地学习C语言编程的技巧和调试方法。

实例3.3 带按键选择的花样灯

任务要求:利用MSP430F249单片机的P1端口控制8个发光二极管LED1~LED8,发光二极管根据P0端口接入的开关K1~K5完成不同的显示花样变换。当K1闭合时,LED1和LED2点亮,延迟0.1 s之后,LED2和LED3点亮,最后是LED7 和LED8点亮,然后重新开始;当K2闭合时,LED1~LED8相当于8位二进制数,延迟0.1 s之后加1并点亮对应的LED;当K3闭合时,先LED1~LED4点亮,延迟0.1 s后LED5~LED8点亮;随后LED1、LED2和LED5、LED6点亮,延迟0.1 s后LED3、LED4和LED7、LED8逐次点亮,最后LED1、LED3、LED4、LED6点亮,延迟0.1 s后LED2、LED4、LED6、LED8点亮,然后重新开始;当K4闭合时,显示如表3-10所示,表中0部分为发光的LED。也就是说,先点亮P1.0~P1.3引脚连接的4个LED,然后让LED从右向左移动,当P1.7引脚连接的LED点亮后,下一步重新点亮P1.0,依次循环。

表3-10 彩灯花样式样图

1)硬件电路设计

在原理图编辑窗口中放置元件,硬件电路如图3.14所示。

2)程序设计

图3.14 实例3.3硬件电路图

程序说明:程序利用五个开关是否闭合来控制LED花样显示。循环中利用了多种不同的算法来处理花样显示;花样1是利用左移来输出两位LED的变换;花样2利用二进制数直接累加输出给端口的方式,虽较为简单,但是显示效果较好;花样3利用了直接端口赋值的方式;花样4利用两个8位的数左移和右移后或运算,得到一张两个LED相对前进的效果;花样5是一种蛇形变换方式,利用了左移运算和或运算得到一种四个LED同时循环点亮的效果。

3)仿真结果与分析

程序的仿真运行,点击运行后可以观察到LED逐渐变换的效果。开关K1闭合,仿真结果如图3.15所示。其他仿真结果读者编程运行,自己观察。

(www.xing528.com)

图3.15 实例3.3带按键控制的花样灯仿真结果图

实例3.4 16个花样灯控制

任务要求:利用MSP430F249单片机的P1和P4端口控制16个发光二极管LED1~LED16,发光二极管有8种花样显示,显示速度可调,由P2端口三个按键K1~K3控制,分别是模式按键、加速按键和减速按键。这三个按键和前面所用的开关不同,按键在按下后会在内部弹性元件的作用下自动弹起。模式按键按下一次,花样显示模式变换一次,按下8次后循环到第一种模式,加速和减速按键可以控制LED的闪烁速度。

分析说明:按照任务要求,16个发光二极管可以组成更加丰富的花样变换,由于MSP430单片机的每个端口是8位,因此需要两个完整的端口来控制发光二极管,这还需要在程序中处理将16位的输出转换为两个8位的输出,此外,这个实例还将介绍程序的模块化设计、函数指针数组等内容。

1)硬件电路设计

16个花样灯控制的硬件电路如图3.16所示。值得注意的是P1和P4端口在连接到LED时,是用的网络标号(Proteus中为lable)Q1~Q16来表示网络连接关系,这样就简化了图纸的连线,否则会导致图纸上连线过多过密,影响到图纸的简洁和美观。

图3.16 16个LED花样灯硬件电路图

2)程序设计

由于16个花样灯的功能较为复杂,将所有的程序代码写在一个文件中不是一个好的程序设计习惯,我们一般采用模块化编程。模块化编程是指将一个较大的程序划分为若干功能独立的模块,对各模块进行独立开发,然后再将这些模块统一合并为一个完整的程序。这是C语言面向过程的编程方法,可以缩短开发周期,提高程序的可读性和可维护性

在单片机程序里,程序比较小或者功能比较简单的时候,我们不需要采用模块化编程,但是,当程序功能复杂、涉及的资源较多的时候,模块化编程就能体现它的优越性了。如前面写过的闪烁灯程序、流水灯程序和花样灯程序,每一个程序都是只用一个源文件编写就能完成,但程序较为复杂,涉及的功能比较多,将程序全部集中在一个源文件里,将导致主体程序臃肿且杂乱,这样做降低了程序的可读性、可维护性和代码的重用率。如果把这三个程序当做三个独立的模块放到主体程序中进行模块化编程,效果就不一样了。

实际上,模块化编程就是模块合并的过程,也是建立每个模块的头文件和源文件并将其加入到主体程序的过程。主体程序调用模块的函数是通过包含模块的头文件来实现的,模块的头文件和源文件是模块密不可分的两个部分,缺一不可。所以,模块化编程必须提供每个模块的头文件和源文件。下面以花样灯为例来介绍模块化编程。首先将16位花样灯的程序分解为三部分,分别是主函数、按键程序和LED显示程序。

(1)建立模块的源文件。

在模块化编程里,模块的源文件是实现该模块功能的变量定义和函数定义,不能定义main函数。建立模块源文件的方法很多,直接在主体程序里新建一个文件,把代码添加进去,保存为.c的文件,然后将该文件加入到主体程序;或者是在程序外建立一个记事本文件,把代码添加进去,保存为.c的文件,然后把文件添加到主体程序里。在这个实例中,把键盘处理代码放在“key.c”中并保存。程序如下。

(2)建立模块的头文件。

模块的头文件就是模块和主体程序的接口,里面是模块源文件的函数声明。建立头文件的方法和建立源文件的类似,只是在保存的时候把文件保存为.h的文件。在这里,我们新建文件;把键盘处理模块的源文件里的函数声明放到文件里并保存为“key.h”。每个模块的头文件最终都要被包含在主体程序里,而且不能重复包含,否则编译器报错,所以在每个模块的头文件里要做一些处理,以防止头文件重复包含。程序如下:

在头文件“delay.h”里,#ifndef…#endif为预编译指令,作用是避免重复包含。头文件的开头两句:“#ifndef KEY_H”和“#define KEY_H”的意思是,如果没有定义“KEY_H”,就定义“KEY_H”。“KEY_H”是这个头文件的标识符,名字可以任意取,但通常的写法是将头文件名改成大写,把点改成下划线组成,一看就知道是头文件的标示符。接下来就是定义头文件的内容,也就是列出函数声明,头文件的最后应该是结束编译指令#endif。

同理,建立LED显示控制的头文件如下:

LED显示控制的C文件如下:

(3)在主程序里包含模块的头文件,完成程序总体设计,把上面的两个文件“key.h”和“led_disp.c”分别添加到程序里。为了体现“主体”区别于模块,把主体程序的源文件命名为“main.c”。程序如下。

从主程序来看,代码非常简洁,便于编程人员理解和修改,更重要的是键盘处理程序和LED显示控制程序可以重复使用于其他设计中。特别要指出的是在led_disp.c文件中有一个代码:

这个代码定义了一个函数指针数组,将8个显示模式的函数地址保存在run数组中,该数组保存的是函数的指针,在主程序中用run[Run Mode]()不同的显示模式,Run Mode为显示模式变量,可以通过模式按键进行修改。

3)仿真结果与分析

点击装载程序运行后可以观察到LED逐渐变换的效果。仿真结果如图3.17所示。

图3.17 实例3.4 16个花样灯仿真结果图

3.3 LED数码管显示

LED数码管是单片机应用系统中常用的输出设备,它由发光二极管组成,用来显示字段,具有结构简单、价格便宜等特点。

通常使用的LED数码管是7段式和8段式LED。8段式比7段式多了一个小圆点,其他的基本相同。所谓的8段就是指数码管里有8个小LED,其中7个长条形的发光管,即a、b、c、d、e、f、g,排列成一个“日”字形,另一个圆点形的发光二极管,即dp,在显示器的右下角作为显示小数点用,通过控制这8个不同的LED的亮灭来显示不同的数字、字母及其他符号,如图3.18所示。

数码管又分为共阴极和共阳极两种类型,如图3.19所示。共阴极是将8个LED的阴极连在一起,让其接地,这样当某一个LED的阳极为高电平时,LED便能点亮;共阳极就是将8个LED的阳极连在一起。图3.18所示为8段共阴极数码管引脚图,两个“GND”引脚连在一起接地。如果是共阳数码管,这两个“GND”引脚则为电源引脚,需连在一起接+5 V电源。

数码管的8段,对应一个字节的8位,a对应最低位,dp对应最高位。所以,如果想让数码管显示数字0,那么共阴数码管的字符编码为00111111,即3F;共阳数码管的字符编码则为11000000,即C0。数码管的字形7段码与十六进制数的对应关系如表3-11所示。从表中可以看出,共阴极与共阳极的字形代码互为补数。

图3.18 8段数码管引脚图

图3.19 数码管结构图

表3-11 LED数码管字符字段编码表

实例3.5 单个数码管显示

任务要求:使用MSP430F249单片机实现单个8段共阴极数码管的显示,依次循环显示0~15的十六进制数,即“0~F”。

分析说明:可设置P1端口的8个引脚分别控制共阴数码管的8段,当I/O端口输出高电平“1”或低电平“0”时,实现每段发光二极管的点亮或熄灭。

1)硬件电路设计

P1.0引脚接共阴极数码管的a段,P1.1引脚接数码管的b段,依次类推,硬件电路如图3.20所示。为了限制每个端口的输出电流在5 m A以内,此处限流电阻R取470Ω。

图3.20 单个数码管显示电路图

2)程序设计

对照表3-11中字形代码与十六进制数的对应关系,设置P1端口按一定规律输出相应代码值。程序如下:

程序说明:此程序中,由于数字字型的编码没有规律,可以使用数组存储这些预先定义的常数,程序中数组led_tab[]内有16个元素,为显示字型“0~F”的段码。当使用程序语句“P1 OUT=led_tab[i]”时,即可将led_tab数组中的第i个元素直接赋给P1OUT。当i从0开始每次加1,P1端口输出字型“0~F”的段码,将数码管对应的字段点亮,显示出所需的字符。另外由于硬件确定后,段码值固定不会改变,因此通过const关键字定义led_tab数组,这样可以把它定义在MSP430F249单片机的内部Flash中,从而节省内部RAM存储器。

3)仿真结果与分析

在IAR编译程序得到7LED.d90文件,并在Proteus原理图中双击MSP430F249单片机,装载可执行文件7LED.d90后运行,可以观察到数码管上的数字依次从0~F变换显示,仿真效果如图3.21所示。

图3.21 单个数码管仿真结果图

实例3.5是单个的数码管显示,在很多应用中需要两个或者更多的数码管显示。

实例3.6 2位数码管加减计数

任务要求:2位数码管显示0~99,带加减计数功能,利用两个按键分别实现加法和减法功能,每按一次,数字增加或者减小1,当增加到99或者减小到0时不变。

分析说明:单个的数码管可以用一个单片机的端口控制,2位的数码管就要占用两个8位的端口,这里我们用单片机的P1和P4端口分别控制两个数码管。P3端口接入三个按键实现加减计数和清零功能。

1)硬件电路设计

这里数码管和单片机I/O端口之间的限流电阻没有采用单个的电阻,而是使用一种称为排阻RN的元件,这种元件是将4个或者8个电阻封装在一起,使用十分方便,减少了元件体积和焊接时间,是一种常用的硬件设计方式。数码管采用两个1位的共阴极数码管,分别用P1和P4控制,当然也可以采用其他端口,这里主要是考虑到仿真时原理图的简洁,另外LED选择的是不带小数点的7段共阴极数码管,硬件电路原理如图3.22所示。

图3.22 2位数码管加减计数硬件电路原理图

2)程序设计

程序说明:程序较为简单,没有采用多模块化程序设计的方式,所有程序在一个文件中。值得注意的是,程序中对加1和减1计数限制了其计数值的范围,当计数值小于10的时候,将十位数输出关闭,以便符合通常的十进制数显示习惯。

3)仿真结果与分析

程序的仿真运行参照前面的实例,点击运行后可以观察到数码管在按键按下后输出的数字。仿真效果如图3.23所示。

4)讨论

一个LED数码管只能显示一位数字,在很多单片机系统中经常要使用多个LED数码管,如要显示时间、温度、压力等。在实例3.5中,一个数码管使用了单片机的8 个I/O端口线输出段码(公共端接GND)。显然,当使用多个数码管时,采用此控制方式会存在问题,如要使用6个数码管,则需要48个通用I/O端口,系统就无法连接其他的外围设备和电路了。另外,采用此方式显示字符时,每个LED都要消耗一定的电流,在极端情况下最多有8个LED工作,如果有多个数码管工作,则消耗的电流非常可观,因此多个数码管的显示驱动系统的实现,有多种不同的方式可以采用,而且在硬件和软件的设计上也是不同的。

当多位数码管并列在一起时,其内部的公共端是独立的,而负责显示数字的段码(即a,b,c,d,e,f,g,dp)全部是连接在一起的。独立的公共端可以控制多位数码管中的某一个数码管点亮,连接在一起的段码可以控制这个能点亮的数码管显示的数字。通常我们把公共端称为“位选线”,通过单片机及外部驱动电路就可以控制任意的数码管显示任意的数字了。

对于多位数码管,有静态显示和动态扫描显示两种显示方式。

图3.23 实例3.6仿真结果图

(1)静态显示。

所谓静态显示,就是把多个数码管的每一段(a~dp)与一个8位并行口连接起来,而公共端则根据数码管的种类连接到“VCC”或“GND”端。图3.24所示为一个4 位LED的静态显示电路。这种连接方式的每一个数码管都需占用一个单独的具有锁存功能的I/O端口,单片机只需把要显示的段码发送到接口电路即可,直到要显示新的数据时,再发送新的段码。

图3.24 4位LED静态显示电路

静态显示方式具有编程简单,显示稳定,CPU使用效率较高等特点,但其要求有8 ×N根I/O端口线,占用I/O端口资源较多,接口电路也较复杂,功耗比较大,因此,在位数较多时往往采用动态扫描显示方式。

(2)动态扫描显示。

所谓动态扫描显示,就是将所有位的段码并联在一起,由一个8位I/O端口控制,而共阴极或共阳极公共端分别由相应的I/O端口线控制。图3.25是一个8位LED动态显示电路。

此方式只需要两个8位I/O端口,一个输出段码,一个控制“位选线”。由于所有数码管的段码都连接到一个8位I/O端口,要想每位显示不同的字符,必须采用扫描

图3.25 8位LED动态显示电路

当数码管显示位数较多时,此方法占用单片机的I/O端口资源较少,需要提供的I/O接口电路也较简单,节省功耗,但其编程难度稍高,单片机要周期性地扫描各数码管,占用CPU的资源较多。

实例3.7 2位一体数码管倒计时

任务要求:使用2位一体的数码管实现30 s的倒计时显示,当按下启动按键时,数码管显示数据从30开始减1,一直到0。倒计时开始后,按键输入无效。

分析说明:根据前述的动态扫描的方式,由P1端口驱动数码管的控制端,P2端口的P2.0、P2.1连接到公共端。键盘输入由P2.2端口接入。

1)硬件电路设计

在原理图编辑窗口中放置元件,硬件电路如图3.26所示。

2)程序设计

图3.26 30 s倒计时硬件电路图

程序说明:2位数码管使用了动态显示的方式,在主程序for循环中,P1端口输出十位数的显示段码后,P2.0置低,此时左边一位数码管显示十位数,延迟2 ms,再显示个位数,延迟2 ms。由于人眼视觉残留的效应,两位数字是同时显示的。按键采用中断的方式,当按下按键时,产生一个下降沿的跳变,在程序中P2IE|=BIT2、P2IES|=BIT2两条语句分别让P2.2中断使能和配置P2.2下降沿中断。中断服务程序为如下代码:

其中#pragma vector=PORT2_VECTOR为定义中断矢量地址,由于外部中断不能自动清除,在软件中利用P2IFG &=~BIT2清除中断标志。

3)仿真结果与分析

点击运行程序,按下启动按键后可以观察到数码管显示的数字减1直到0;在倒计时开始后,按键无效;直至计数为0才能重新启动倒计时。仿真效果如图3.27所示。

图3.27 30 s倒计时仿真结果图

实例3.8 4位一体数码管静态显示

任务要求:用静态显示方式,利用单片机控制4位一体数码管中每一位独立显示,从0开始,每次加1,一直增至9999后归零重新开始。

分析说明:4位数码管如果用静态显示方式,需要的I/O端口为32个,导致占用大量的端口,且由于数码管的功耗较高,单片机同时驱动32个I/O端口会超过其极限输出电流,因此利用锁存器,将单片机的数据输出轮流送给4个锁存器,数据被保持在锁存器中实现静态显示。这里选择74 HC573作为锁存器。其原理如图3.28所示。

图中74HC573的D0~D7为输入,Q0~Q7为输出,OE为输出使能引脚,LE为锁存引脚。其功能如下:当OE使能引脚为高电平时,不管LE和D0~D7的信号如何变化,Q0~Q7是一种高阻态,即相当于与之连接的电路断开,只有在OE为低电平时,输出才有效;LE锁存引脚为高电平,Q0~Q7跟随输入的变化,当LE引脚出现从高到低的跳变时,输出Q0~Q7与输入D0~D7相同,当D0~D7变化时,输出保持不变。这样为驱动4个数码管,可以使用4片74HC573,将它们的输入端都接到单片机的P1端口,而锁存端LE分别接到单片机其他不同的I/O端口,输出端Q0~Q7接数码管的输入端,利用锁存端的下降沿把需要显示的数据锁存,当单片机将4片74HC573的数据锁存完成,就可以实现4个数码管的静态驱动。

图3.28 74HC573逻辑图

1)硬件电路设计

硬件电路如图3.29所示。

图3.29 实例3.8硬件电路图

2)程序设计

程序说明:本例程序较为简单,在主循环中对4片74HC573分别进行数据锁存处理,锁存的时序是先将LE信号置低,这样74HC573输出不变;再将显示的数据通过P1端口送到74HC573的D0~D7;通过将LE置高再置低产生一个下降沿,数据就会被锁存到74HC573中。

3)仿真结果与分析

运行加载程序后其仿真效果如图3.30所示。

图3.30 实例3.8仿真结果图

实例3.9 8位一体数码管动态显示时钟

任务要求:用动态显示方式,利用单片机控制8位一体数码管,使其两位一组,分别显示时、分、秒,实现时钟的功能。

1)硬件电路设计

MSP430F249单片机的P1端口控制8位一体数码管的段码,图3.31为其硬件原理图。图中采用了8个共阴极的LED数码管。单片机的P3端口作为位扫描控制端口,P3.0~P3.7分别与LED0~LED7的公共端COM引脚连接。

与静态方式的数码管驱动电路相比,图3.31所示的电路图中占用了16个I/O端口线。8个数码管动态显示只需要两个8位端口,其中P1控制段码,P3控制位选线。动态扫描的原理是:由P3端口向每个位轮流输出扫描信号,使每一瞬间只有一个数码管被选通(共阴极低电平选通,共阳极高电平选通),然后由P1送入该位所要显示的字形码,点亮该位字形段显示的字形。这样在P1送出的段码和P3送出的位选线配合控制下,就可以使各数码管轮流点亮显示各自的字符。虽然显示器的几位数码管是依次被点亮的,但只要每位点亮时间超过1 ms,隔一段时间使之再显示一遍,如此不断重复扫描,只要扫描频率足够快(>50 Hz),由于人的视觉惰性,看不出闪烁。动态扫描一般用软件实现,可以采用软件延时或者定时器延时来得到。

图3.31 8位数码管动态扫描时钟显示原理图

2)软件设计

根据硬件电路可以看出,在任何一个时刻,P3.0~P3.7中只能有一个I/O端口输出低电平,即只有一位数码管亮。同时P1端口要输出该位相应的段码值。即使显示的内容没有变化,也要不停的进行循环扫描处理。

软件的设计应保证从外表看数码管显示的效果要连续(即在人眼里各个数码管全部点亮),亮度均匀,同时没有拖尾现象。单片机为了保证各数码管显示的效果不产生闪烁情况,让数码管看起来好像是全部点亮,就首先必须在1 s中内循环扫描8个数码管的次数应大于25次,这里是利用了人眼的影像滞留效应。第二要考虑的是,在25 ms时间间隔中,要逐一轮流点亮8个数码管,那么每个数码管点亮的持续时间要相同,这样亮度才能均匀。第三个要考虑的要点为每个数码管点亮的持续时间,这个时间长一些的话,数码管的亮度高一些,反之则暗一些。通常,每个数码管点亮的持续时间为1~2 ms。我们将每个数码管的点亮持续时间定为2 ms,那么8个数码管扫描一遍的时间为16 ms,因此,单片机还有9 ms的时间处理其他事件,为了简单起见,本例中还是使用了delayus()软件延时函数进行定时,在以后的章节里,将介绍使用MSP430的定时器产生更精确的毫秒计时脉冲。

  }

 }

3)仿真结果与分析

运行加载程序后可以观察到时钟运行的效果。仿真效果如图3.32所示。

图3.32 8位数码管动态显示时钟仿真效果图

思考与练习

1.简述MSP430单片机I/O端口的特性和初始化步骤。

2.将MSP430F249单片机的P1.0、P1.1、P1.2分别接红色、绿色和蓝色的LED,低电平输出点亮;P1.5、P1.6、P1.7接按键K1、K2、K3。当K1和K2同时按下时,红色LED亮;当K2或者K3按下时,绿色LED亮;K1单独按下时,蓝色LED亮,等待1 s时间后K3再按下,蓝色LED灭。利用Proteus和IAR完成硬件和软件设计。

3.MSP430F249单片机外接16个LED成一排,要求实现如下功能:初始时最左和最右的LED点亮,并同时向中间移动(合幕),相遇后停留1 s,再向两边移动(拉幕),到达两侧停留1 s;循环运行。利用Proteus和IAR完成硬件和软件设计。

4.MSP430F249单片机外接LED和数码管,模拟一个路口的红绿灯控制功能。正向绿灯亮10s,正向数码管倒计时到0,绿灯灭,红灯亮。同时反向绿灯亮10 s,反向的数码管倒计时,如此循环反复。

5.数码管静态显示和动态显示各有什么特点?各用在什么场合?

6.用8位数码管设计一数字时钟,要求利用P1或者P2外接按键K1~K4实现时间校正的功能,K1~K3完成时分秒的校正,K4为确认按键。要求按键的处理利用中断方式实现。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈