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 "0"b + c, // Displays "1"a + b + d + e + g, // Displays "2"a + b + c + d + g, // Displays "3"b + c + f + g, // Displays "4"a + c + d + f +g, // Displays "5"a + c + d + e + f + g, // Displays "6"a + b + c, // Displays "7"a + b + c + d + e + f + g, // Displays "8"a + b + c + d + f + g, // Displays "9"a + b + c + e + f + g, // Displays "A"c + d + e + f + g, // Displays "B" a + d + e + f, // Displays "C"b + c + d + e + g, // Displays "D"a + d + e + f + g, // Displays "E"a + e + f + g, // Displays "F"a + c + d + e + f, // Displays "G"b + c + e + f + g, // Displays "H" e + f, // Displays "I"b + c + d + e, // Displays "J"b + d + e + f + g, // Displays "K"d + e + f, // Displays "L" a + c + e + g, // Displays "M" a + b + c + e + f, // Displays "N" c + e + g, // Displays "n"c + d + e + g, // Displays "o"a + b + c + d + e + f, // Displays "O"a + b + e + f + g, // Displays "P"a + b + c + f + g, // Displays "Q" e + g, // Displays "r"a + c + d + f +g, // Displays "S"d + e + f + g, // Displays "t"a + e + f , // Displays "T" b + c + d + e + f, // Displays "U"c + d + e, // Displays "v" b + d + f + g, // Displays "W"b + c + d + f + g, // Displays "Y" a + b + d + e + g, // Displays "Z"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] = "\0\0\0\0\0\0\0\0"; //初始状态 不显示
动态扫描时,函数每1.9ms(设的看门狗定时中断)调用一次显示函数,每次显示一位(为了让中断占用更少的时间,这样中断里只需赋值即可)。函数如下:
void Display() {static char i = 0; //记录扫描显示到哪位CTRL_OUT = 1<<i;DATA_OUT = Nixie[i];i++;if(i>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; //看门狗内部定时器模式16msIE1 |= 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:
void NixiettubeClear() {for(int i = 0;i < 8;i++)Nixie[i] = Tab[SP]; //显示空格 }
程序比较简单,这里就不多解释了。
数码管的程序就这么多了,所有函数都列出来了。下面开始介绍printf的移植,具体过程不再详细说了,详细过程参考:MSP430程序库<四>printf和scanf函数移植。这里主要介绍所需程序。
#include <stdio.h> #include "ctype.h" /*isdigit函数需要该头文件*/ #include "Nixietube.h"int putchar(int ch) {//'\f'表示走纸翻页,相当于清除显示if(ch=='\n'||ch=='\r')NixiettubeClear();//数字和对应ASCII字母之间差0x30 '1'=0x31 '2'=0x32... //isdigit也是C语言标准函数if(isdigit(ch))NixiettubeInsertChar(ch-0x30); //若字符是数字则显示数字else //否则,不是数字,是字母{switch(ch) //根据字母选择程序分支{case 'A': case 'a': NixiettubeInsertChar(AA);break; //字符Acase 'B': case 'b': NixiettubeInsertChar(BB);break; //字符Bcase 'C': case 'c': NixiettubeInsertChar(CC);break; //...case 'D': case 'd': NixiettubeInsertChar(DD);break; case 'E': case 'e': NixiettubeInsertChar(EE);break;case 'F': case 'f': NixiettubeInsertChar(FF);break;case 'G': case 'g': NixiettubeInsertChar(GG);break;case 'H': case 'h': NixiettubeInsertChar(HH);break;case 'I': case 'i': NixiettubeInsertChar(II);break; case 'J': case 'j': NixiettubeInsertChar(JJ);break;case 'K': case 'k': NixiettubeInsertChar(KK);break;case 'L': case 'l': NixiettubeInsertChar(LL);break;case 'M': case 'm': NixiettubeInsertChar(mm);break;case 'N': NixiettubeInsertChar(NN);break;case 'n': NixiettubeInsertChar(nn);break;case 'O': NixiettubeInsertChar(OO);break;case 'o': NixiettubeInsertChar(oo);break;case 'P': case 'p': NixiettubeInsertChar(PP);break; case 'Q': case 'q': NixiettubeInsertChar(QQ);break; case 'R': case 'r': NixiettubeInsertChar(rr);break; case 'S': case 's': NixiettubeInsertChar(SS);break; case 'T': case 't': NixiettubeInsertChar(tt);break; case 'U': case 'v': NixiettubeInsertChar(UU);break; case 'V': case 'u': NixiettubeInsertChar(VV);break; case 'W': case 'w': NixiettubeInsertChar(WW);break; case 'Y': case 'y': NixiettubeInsertChar(YY);break; //...case 'Z': case 'z': NixiettubeInsertChar(ZZ);break; //字符Zcase '-': NixiettubeInsertChar(NEG);break;//字符-case '.': NixiettubeInsertChar(DOT);break;//小数点,直接显示在右下角case ' ': NixiettubeInsertChar(SP);break; //空格default : NixiettubeInsertChar(SP);break;//显示不出来的字母用空格替代} } return(ch); //返回显示的字符(putchar函数标准格式要求返回显示字符) }
头文件必须包含stdio.h,这样告诉编译器printf调用时,用这里的putchar函数。然后判断字符,分类进行显示,不能显示的空一格。
数码管的程序就完成了,如果需要可以自己添加改写函数,如:当和键盘共同使用时,如果键盘移植了scanf函数,并且支持退格;可以改写函数-让数码管的putchar支持退格操作。或者用的是我的键盘程序,需要10多ms调用一次键盘处理函数,这样可以和这个数码管扫描公用一个中断:
void Display() {static char i = 0; //记录扫描显示到哪位CTRL_OUT = 1<<i;DATA_OUT = Nixie[i];i++;if(i>7){i = 0;KeyProcess();} }
这样改写,然后把键盘的中断去掉(别忘了key.h包含和加入KeyProcess(); 的声明;如果程序中有两个指向同一个中断时,会编译错误);这样就可以键盘、和数码管共同使用了。
- 使用示例:
使用方法还是和之前一样,工程中加入Nixietube.c文件,然后在要调用的地方加入Nixietube.h的包含;如puchr函数,和示例工程的main.c
main.c调用的方式如下:
#include <msp430x16x.h> #include <stdio.h> #include "Nixietube.h"void ClkInit() {char i;BCSCTL1 &= ~XT2OFF; //打开XT2振荡器IFG1&=~OFIFG; //清除振荡错误标志while((IFG1&OFIFG)!=0){for(i=0;i<0xff;i++);IFG1&=~OFIFG; //清除振荡错误标志}BCSCTL2 |= SELM_2+SELS+DIVS_3; //MCLK为8MHz,SMCLK为1MHz }void main( void ) {// Stop watchdog timer to prevent time out resetWDTCTL = WDTPW + WDTHOLD;ClkInit();NixiettubeInit();_EINT();//while(1){NixiettubeDisplayChar(AA,5);NixiettubeDisplayChar(DOT,5);NixiettubeInsertChar(2);NixiettubeInsertChar(DOT);NixiettubeInsertChar(2);printf("%1.2f",1.2);} }
包含msp430的头文件,以便使用430单片机的先关资源;加入stdio.h以使用printf函数;加入Nixietube.h使用数码管的相关程序。
还要注意,为了数码管正常显示,必须打开总中断,以使数码管动态扫描显示。另外,本程序单步调试看不到数码管正常显示,因为没有扫描。只有全速运行才可以看到数码管的显示情况。
数码管的程序就到这里,不足之处,欢迎讨论提出建议。
附件:程序库
作者:给我一杯酒
出处:http://Engin.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,转载保留此段文字并且注明出处;谢谢。
转载于:https://www.cnblogs.com/Engin/archive/2011/08/23/2151130.html
MSP430程序库九数码管显示相关推荐
- 实验九、 键盘扫描及数码管显示实验
实验九. 键盘扫描及数码管显示实验 1.实验目的 学习了解键盘扫描的基本原理. 掌握通过并行接口芯片对键盘进行扫描并在多位数码管显示数字的方法. 2.实验内容 编写程序,实现如下功能:初始时数码管无显 ...
- c语言实现7段数码管显示,七段数码管显示实验.doc
七段数码管显示实验 单 片 机 实 验 报 告 实验九 七段数码管显示实验 实验目的 学习七段数码管的工作原理: 学习数码管与8051单片机的接口方法: 掌握动态扫描显示技术. 实验原理 如图4.9- ...
- 简易计算机led数码管单片机课设,单片机课程设计报告--简易计时器——LED?数码管显示接口技术应用.docx...
文档介绍: 文华学院单片机原理及应用课程设计报告姓名: 学号: 学部(系): 专业年级: 指导老师: 201 6年12月5日目录一标题--------------------- 1 二设计内容,设计要 ...
- Protues 基于51单片机的DS18B20温度采集:键盘输入温度上下限_超出设定温度范围报警_8数码管显示
功能实现: 1.设计单片机与16按键的矩阵式键盘接口以及8数码管的接口电路,测试显示和按键功能. 2.设计单片机与DS18B20的接口电路,实现数字温度信息的采集,然后编程处理采集到的数据,得到温度值 ...
- SW6206超级华为快充5V5A,全协议OPPO闪充、自带电量计量、LED 灯/数码管显示
深圳市展嵘电子有限公司 有需要的上帝可联系小陈:136-6225-3950 : 3412-1522-98 SW6206 是一款高集成度的多协议双向快充移动电源专用多合一芯片,支持A+A+B+C+L 口 ...
- c语言数码管数字时钟程序,数码管显示模拟8位时钟C语言程序设计
原标题:数码管显示模拟8位时钟C语言程序设计 //数码时钟设计 #include // 包含寄存器定义的头文件 unsigned char Tab[ ]={0xc0,0xf9,0xa4,0xb0,0x ...
- FPGA基础知识极简教程(9)七段数码管显示的Verilog简单设计
博文目录 写在前面 正文 七段数码管原理 七段数码管译码表 单个七段数码管显示verilog设计 多个数码管动态扫描显示 参考资料 交个朋友 写在前面 作为FPGA的基础知识教程怎么能少得了这个简单的 ...
- 【STM32 .Net MF开发板学习-25】LED数码管显示
在单片机系统中,LED数码管的应用是很常见的,不过对我们偏软件开发的人来说,要想研究LED还得储备一定的知识才能进行近一步的工作.不过采用.NET Micro Framework系统,我们马上就可以站 ...
- MSP430程序库五SPI同步串行通信
SPI总线系统是一种同步串行外设接口:是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越 ...
最新文章
- 如何利用pyecharts绘制炫酷的关系网络图?
- linux虚拟网卡名不是eth0,linux不能启动虚拟网卡eth0
- python中递归函数的实例_Python 递归函数详解及实例
- 美剧中常用地道英语口语,快收了
- oraclek导出表_Oracle导出DMP文件的两种方法
- python文件分发_python 写一个文件分发小程序
- java的成员方法_java编程中的成员方法是什么?
- Django之templates模板
- 美国顶尖大学的博士是怎样练成的?
- MySQL基础——DDL语句
- 淘宝/天猫获得淘口令真实url API
- 基于JavaWeb的微博系统设计与实现
- 风变编程python网址_风变编程《Python基础语法+爬虫精进》
- 手机消息推送方案综述
- matlab quadratic,请教几个quadratic programming的问题
- MacbookPro中 Idea快捷建(记录中)
- hive: Error in acquiring locks
- marvin java_Java开源图像处理框架Marvin介绍
- poi2009 切题记
- 如何又快又好地写出优质PPT