MSP430程序库九数码管显示

MSP430程序库<九>数码管显示

数码管也是单片机系统最常用的输出设备之一(还有液晶、发光二极管等)。七段(这里用的是8段,有小数点)数码管可以完成显示0-9数字和一部分的英文字符如:A、b。本文实现的程序完成显示数字和可显示的英文字符;同时完成数码管显示的printf函数的移植,以支持printf的格式化字符等好用的特点(我用的数码管8个排为一排,方便数字等的显示)。

?

硬件介绍:

这里所用到的硬件资源包括8个数码管、和msp430单片机的两个8位IO口(这里用的是P3和P5口,如有改变,可以通过宏定义更改)。

数码管是8个共阴的数码管,a-h 8段通过一个200Ω的电阻接到430单片机的P5口。共阴端是由单片机的P3口控制,单片机的一位IO通过一个三极管接到数码管的共阴端,以完成位选。

单片机的P3口时数码管的位选口,某位为高则选中;P5口时段选口;要数码管显示时,通过P3位选,选中某个数码管亮,P5段选选择8段(a-h)中的那些亮,从而控制某一位显示数字或字符。

要同时显示多个数码管,就要动态扫描;动态扫描时,本程序选用的是由看门狗的中断扫描显示:每1.9ms显示其中的一位,动态扫描显示每一位,从而让数码管看起来是同时亮的。

? 程序实现:

数码管显示首先要有一个数码管显示的断码表(完成数字和字符到数码管段值的表),程序中采用了《MSP430系列单片机系统工程设计与实践》这本书推荐的方式实现的这个数码表:先用宏定义定义每段对应的单片机要输出的段值,然后再实现是个表,当硬件改变时,只需更改前面的每段的段值定义即可,改动的地方少了很多,代码如下:

/*宏定义,数码管a-h各段对应的比特,更换硬件只用改动以下8行*/ #define a 0x01 // AAAA #define b 0x02 // F B #define c 0x04 // F B #define d 0x08 // GGGG #define e 0x10 // E C #define f 0x20 // E C #define g 0x40 // DDDD HH #define h 0x80 //小数点 /*用宏定义自动生成段码表,很好的写法,值得学习*/ /*更换硬件无需重写段码表*/ const char Tab[] = { a + b + c + d + e + f, // Displays \\ b + c, // Displays \ a + b + d + e + g, // Displays \ a + b + c + d + g, // Displays \ b + c + f + g, // Displays \ a + c + d + f +g, // Displays \ a + c + d + e + f + g, // Displays \\ a + b + c, // Displays \ a + b + c + d + e + f + g, // Displays \8\ a + b + c + d + f + g, // Displays \\ a + b + c + e + f + g, // Displays \\ c + d + e + f + g, // Displays \ a + d + e + f, // Displays \ b + c + d + e + g, // Displays \\ a + d + e + f + g, // Displays \ a + e + f + g, // Displays \ a + c + d + e + f, // Displays \ b + c + e + f + g, // Displays \ e + f, // Displays \ b + c + d + e, // Displays \ b + d + e + f + g, // Displays \ d + e + f, // Displays \ a + c + e + g, // Displays \ a + b + c + e + f, // Displays \ c + e + g, // Displays \ c + d + e + g, // Displays \ a + b + c + d + e + f, // Displays \\ a + b + e + f + g, // Displays \ a + b + c + f + g, // Displays \ e + g, // Displays \ a + c + d + f +g, // Displays \ d + e + f + g, // Displays \ a + e + f , // Displays \ b + c + d + e + f, // Displays \ c + d + e, // Displays \ b + d + f + g, // Displays \ b + c + d + f + g, // Displays \ a + b + d + e + g, // Displays \\ g, // Displays \ h, // Displays \ 0 // Displays \\}; #undef a #undef b #undef c #undef d #undef e #undef f #undef g 0-9的位置对应显示0-9,之后的是A开始往后显示,为了方便访问这个表格,定义了AA等一系列的常量,方便访问这个表。

#define AA 10 #define BB AA+1 #define CC BB+1 #define DD CC+1 #define EE DD+1 #define FF EE+1 #define GG FF+1 #define HH GG+1 #define II HH+1 #define JJ II+1 #define KK JJ+1 #define LL KK+1 #define mm LL+1 #define NN mm+1 #define nn NN+1 #define oo nn+1 #define OO oo+1 #define PP OO+1 #define QQ PP+1 #define rr QQ+1 #define SS rr+1 #define tt SS+1 #define TT tt+1 #define UU TT+1 #define VV UU+1 #define WW VV+1 #define YY WW+1 #define ZZ YY+1 #define NEG ZZ+1 /* - */ //负号 #define DOT NEG+1 /* . */ //小数点 #define SP DOT+1 /* 空白 */ //空格 A从10开始访问这个表格,如果要显示A只需这样用Tab[AA],即可得到需要的段值,AA-空格的宏定义放在H文件里,方便其他文件访问(当要调用显示函数的时候需要AA等宏定义)。为什么是AA而不是A呢?主要原因是单字母的有几个已经在单片机430的头文件里定义了,为了访问的时候一致,就都用两个字母的了。

为了动态扫描,这里定义了一个全局数组(数码管的程序可以访问)Nixie[8]在这个里面的8个char对应8个数码管要显示的段值。初始值是8个数码管都不显示:

char Nixie[8] = \; //初始状态 不显示 动态扫描时,函数每1.9ms(设的看门狗定时中断)调用一次显示函数,每次显示一位(为了让中断占用更少的时间,这样中断里只需赋值即可)。函数如下:

void Display() { static char i = 0; //记录扫描显示到哪位 CTRL_OUT = 1<7) i = 0; } 这个函数供中断调用,i用来保存要显示哪一位。CTRL_OUT 、DATA_OUT 是宏定义的位选和段选口。中断程序如下:

#pragma vector=WDT_VECTOR __interrupt void WDT_ISR() { Display(); } 中断只调用了一个函数,这样很方便换其他中断来定时。

中断是必须初始设置的,还有IO口,要设为输出方向 ,初始化函数完成数码管用到的单片机资源的初始工作:

void NixiettubeInit() { WDTCTL = WDT_ADLY_1_9; //看门狗内部定时器模式16ms IE1 |= WDTIE; //允许看门狗中断 CTRL_DIR_OUT; DATA_DIR_OUT; } 首先,设置中断并允许中断;然后设置位选和段选所用的端口为输出方向。CTRL_DIR_OUT; DATA_DIR_OUT; 和刚才用到的两个OUT的宏定义如下:

#define DATA_DIR_OUT P5DIR|=0XFF #define CTRL_DIR_OUT P3DIR|=0XFF #define DATA_OUT P5OUT #define CTRL_OUT P3OUT 这样处理之后,要显示数字就很简单了:只需把要显示的数字或字符的段码值放入Nixie[8]数组对应的位置即可,如显示韩输入下:

void NixiettubeDisplayChar(char ch,char addr) { if(ch == DOT) //小数点,不需单独占一位 { Nixie[addr] |= Tab[ch]; } else { Nixie[addr] = Tab[ch]; } } 如果是小数点,放入对应位置的h段即可,其他直接覆盖。 插入字符函数:在最右端插入数字或字符.

void NixiettubeInsertChar(char ch) { if(ch == DOT) ////小数点,不需单独占一位 { Nixie[0] |= Tab[ch]; return; } for(int i = 7;i > 0;i--) Nixie[i] = Nixie[i - 1]; //已显示字符左移一位 Nixie[0] = Tab[ch]; } 这个也是先判断小数点,小数点直接放到h段,其他的,则要已显示的左移再覆盖最右一位,源程序的注释很详细,可具体才、可以下载附件的程序库。

数码管清除函数,这个函数把数码管全部显示去掉,即把缓存数组内每项都置为0:

联系客服:779662525#qq.com(#替换为@) 苏ICP备20003344号-4