这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 资深工程师单片机实战项目精讲(连载),由易到难连续分享

共31条 1/4 1 2 3 4 跳转至

资深工程师单片机实战项目精讲(连载),由易到难连续分享

助工
2015-01-07 13:50:43     打赏

资深工程师单片机实战项目精讲(连载),由易到难连续分享


友情提示:如果想及时查看本连载贴分享的内容,请关注微信公众号:单片机精讲吴鉴鹰 随时随地都可以查看项目分享

搜索微信公众号:单片机精讲吴鉴鹰 或者微信扫一扫


Hi!大家好,我叫吴鉴鹰,100%中国制造,长181cm,净重70kg。采用人工智能,各部分零件齐全,软硬件运转稳定,经二十多年的运行,属质量信得过产品。是一名从业10多年的单片机工程师,长年从事单机、DSP、fpga、PLC以及触摸屏的项目开发,自信比牛顿更懂单片机、比诸葛亮更会玩DSP、比汉武大帝懂得什么是指针,这年头就得玩一个综合实力。(以上的话,绝非自我夸奖,仅供娱乐


人还不错吧!除了长得帅点,也没什么缺点!哈哈......(估计有人想扇鉴鹰了,还骂道:打你个臭不要脸的)
闻得eepw上有一批志同道合之士,愿意一道交流技术,于是花以时日浏览之,果然不乏卧虎藏龙之辈,鉴鹰深感钦佩,感谢这些前辈同行能够分享自己的项目经验和学习心得。也通过这些有技术含量的帖子博客获益不少。
回想当年鉴鹰刚刚大学本科毕业不久,进入一家大型国企,保守传统思想——“教会徒弟,饿死师傅”这种陋习的影响,只能靠自己死磕书本,硬啃项目慢慢才取得一点进步。所以后来干脆辞职再次回到电子科技大学读了三年研究生!为了让现在毕业的毕业的年轻人不要重蹈鉴鹰当年的覆辙,我也愿意将自己多年积累的一点经验分享给大家,想让更多的年轻人看到,获得一点点帮助就足矣!


鉴鹰将会逐步分享自己的一点项目经验和学习心得,由于水平能力有限,纰漏之处,还望各位同行指出。
每一个项目会提供原理图、源程序还有仿真图。

欢迎各位看官,各位同仁能够客观指出其中的问题,鉴鹰一定及时改进。


1、吴鉴鹰单片机实战项目精讲(连载)之基于单片机的数字电子钟设计(一)——硬件介绍

http://forum.eepw.com.cn/thread/267046/1#2

2、吴鉴鹰单片机实战项目精讲(连载)之基于单片机的数字电子钟设计(二)——源代码设计

http://forum.eepw.com.cn/thread/267046/1#3

3、吴鉴鹰单片机实战项目精讲(连载)之摇摇棒的制作(一)——硬件介绍

http://forum.eepw.com.cn/thread/267046/1#4

4、吴鉴鹰单片机实战项目精讲(连载)之摇摇棒的制作(二)——源程序介绍

http://forum.eepw.com.cn/thread/267046/1#5

5、吴鉴鹰单片机项目详细解析系列连载之基于单片机的电子秤设计(一)——硬件原理介绍

http://forum.eepw.com.cn/thread/267046/1#10

6、吴鉴鹰单片机项目详细解析系列连载之基于单片机的电子秤设计(二)——源代码设计介绍

http://forum.eepw.com.cn/thread/267046/2#16

7、吴鉴鹰单片机项目详细解析系列(连载)之基于单片机的微机键盘的运用(一)——原理介绍

http://forum.eepw.com.cn/thread/267046/2#17

8、吴鉴鹰单片机项目详细解析系列(连载)之基于单片机的微机键盘的运用(二)——相关的程序编写

http://forum.eepw.com.cn/thread/267046/2#18

9、吴鉴鹰单片机项目详细解析系列(连载)如何提高单片机的抗干扰能力(一)

http://forum.eepw.com.cn/thread/267046/2#19

10、吴鉴鹰单片机项目详细解析系列(连载)如何提高单片机的抗干扰能力(二)

http://forum.eepw.com.cn/thread/267046/2#20

11、吴鉴鹰单片机项目详细解析系列(连载)之基于单片机的超声波测距仪设计(一)——硬件设计一

http://forum.eepw.com.cn/thread/267046/3#23

12、吴鉴鹰单片机项目详细解析系列(连载)之基于单片机的超声波测距仪设计(二)——硬件设计二

http://forum.eepw.com.cn/thread/267046/3#24

13、吴鉴鹰单片机项目详细解析系列(连载)之基于单片机的超声波测距仪设计(三)——软件设计(一)

http://forum.eepw.com.cn/thread/267046/3#30

14、吴鉴鹰单片机项目详细解析系列(连载)之基于单片机的超声波测距仪设计(四)——软件设计(二)

http://forum.eepw.com.cn/thread/267046/4#31

15、吴鉴鹰单片机项目详细解析系列(连载)之卡通人物12864显示(一)

http://forum.eepw.com.cn/thread/267046/4#34

16、吴鉴鹰单片机项目详细解析系列(连载)之卡通人物12864显示(二)——源程序代码

http://forum.eepw.com.cn/thread/267046/4#35

17、吴鉴鹰单片机项目详细解析系列(连载)之美女人物12864显示(一)——原理介绍

http://forum.eepw.com.cn/thread/267046/5#43

18、吴鉴鹰单片机项目详细解析系列(连载)之美女人物12864显示(二)——源程序代码

http://forum.eepw.com.cn/thread/267046/5#44

19、吴鉴鹰单片机项目详细解析系列(连载)之12864的正弦波的显示(一)——原理图

http://forum.eepw.com.cn/thread/267046/5#45

20、吴鉴鹰单片机项目详细解析系列(连载)之12864的正弦波的显示(二)——源程序

http://forum.eepw.com.cn/thread/267046/5#49

21、吴鉴鹰单片机项目详细解析系列(连载)之12864的武术动画的显示(一)——展示

http://forum.eepw.com.cn/thread/267046/5#50

22、吴鉴鹰单片机项目详细解析系列(连载)之12864的武术动画的显示(二)——程序设计

http://forum.eepw.com.cn/thread/267046/6#51











关键词: 资深工程师     吴鉴鹰     单片机     实战项目     连载    

助工
2015-01-07 13:55:42     打赏
2楼

1、吴鉴鹰单片机实战项目精讲(连载)之基于单片机的数字电子钟设计(一)——硬件介绍

 

相关硬件原理图点击下载:

吴鉴鹰单片机项目详细解析系列之基于单片机的数字时钟设计原理图.pdf

 

 

现在来第一讲,详细解析如何制作基于单片机的数字时钟,提供详细的硬件原理图和软件程序。
      开关K1K1 = 0时,时钟正常运行,此时不允许调整时钟。数码管的高两位显示小时,后两位显示分钟,led每闪一次表示时钟运行一次,在调整的过程中,led是停止发亮的。
一、 按键、开关功能说明:
      *  按键RESET:按下能复位程序。
      *  按键PULSE:提供单脉冲,从而实现单片机对外部脉冲的计数,利用单脉冲实现相应的位加一。
      *  开关K0K0 = 0能调整分位,K0 = 1能调整时位。
      *  开关K2:k2为高电平时,使单脉冲输入至INT1,通过外中断实现相应值的加一功能。

二、地址分配和链接
      *  P2.7:  和写信号一起组成字位口的片选信号,字位口的对应地址为8000H
      *  P2.6:  和写信号一起组成字位口的片选信号,字位口的对应地址为4000H
      *  D0~D7: 单片机的数据总线,LED显示的内容通过D0~D7数据线从单片机传到LED
      *  P2.0~P2.5:单片机的P2口,和2764的高位地址线相连,决定2764中的存储单元的地址。
      *  P1.4~P1.7: 单片机的P1端口,和发光二极管L1~L4相连,通过单片机的P1.4~P1.7控制,所以显示秒表和时钟的时间变化。
      *  P1.0: 和开关K0相连,决定时间调整的字位。
      *  P1.1 :  和开关K1相连,决定时间运行的模式。
      *  P1.2: 和开关K2相连,决定外中断的模式选择。

三、整体功能简介
      LED显示模块与单片机的链接中,对LED显示模块的读写和字位、段码的选择通过口P2.6\P2.7完成的。
      外部存储器2764是通过锁存器373和单片机相连,并且通过P2端口的相关信号线进行地址的分配。地址范围是0000H~1FFFH

 


助工
2015-01-07 14:10:08     打赏
3楼

2、吴鉴鹰单片机实战项目精讲(连载)之基于单片机的数字电子钟设计(二)——源代码设计

 

*程序:吴鉴鹰数字电子钟的设计                                                           
** 这一讲的主要内容: 数字电子钟的设计原理和程序                                                                                
** 功能描述:  
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.17


备注:有什么错误的地方,欢迎各大同仁指正


O(∩_∩)O~
*******************************************************/
//变量定义和头文件的调用
//定义头文件和各个输入管脚以及变量声明
#include
#include
#define  uint unsigned int
#define  uchar  unsigned char




/*定义字型字位口*/
#define  DIGPORT  XBYTE  [0X8000]
#define  WORDPORT  XBYTE [0X4000]


/*定义P1口各管脚*/
sbit  K0 = P1^0;
sbit  K1 = P1^1;
sbit  K2 = P1^2;
sbit  BEEP = P1^3;
sbit  L0 = P1^4;
sbit  L1 = P1^5
sbit  L2 = P1^6;
sbit  L3 = P1^7;


uchar  data  BUFFER[2]  = {0,0};  //显示的缓存数组,依次为低位、高位
uchar  data  CLOCK[4] = {0,0,0,0};
uchar  data  SECOND[2] = {0,0};


/*定义运行状态*/
uchar  data  STATE = 0;
/*STATE = 0;秒表*/
/*STATE = 4,或者7,时钟运行*/
/* STATE = 6,时钟时调整 */


bit  bdata  SND = 0;    /*  秒表START(开始)  */
bit  bdata  RST = 0;     /*秒表RESET(复位)*/


/*数码管显示编码“0”-“9”,"A","-"*/
uchar  code  TABLE[] = {0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F,0X77,0X40};


/******************************************************
*程序:主程序                                                                                                                         
** 功能描述: 主干程序 
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.17


备注:有什么错误的地方,欢迎各大同仁指正


O(∩_∩)O~
*******************************************************/
void  main()
{
      uchar   stabak;
      P1 = 0X0F;
      EA = 1;
      IT1 = 1;
      ET0 = 1;
      TMOD = 0X61;
      TH0 = -5000/256;
      TL0 = -5000%256;
      TH1 = 0XFF;
      TL1 = 0XFF;
      T2CON = 0;
      TH2 = -5000/256;
      TL2 = -5000%256;


       K0 = 1;
       K1 = 1;
       K2 = 1;
       STATE = P1&0X07;
       stabak = STATE;


      for(;;)
    {
           switch()
        {
                case 0:
                {
                    EX1 = 0;
                    ET1 = 1;
                    ET2 = 1;
                    TR1 = 1;
                    SND = 1;
                    L1 = 1;    
                    L0 = 0;
                    L2 = 0;
                    SECOND[0] = 0;
                    SECOND[1] = 0;
                }break;


                 case   5:
                {
                          IE1 = 0;
                          EX1 = 1;
                          ET1 = 0;
                          ET2 = 0;
                          TR0 = 0;
                          L0 = 1;
                          L1 = 0;
                          L2 = 0;
                }break;


                case  6:
               {
                    IE1 = 0;
                    EX1 = 1;
                    ET1 = 0;
                    ET2 = 1;
                    TR0 = 0;
               }break;


                  default:
               {
                   EX1 = 0;
                   ET1 = 0;
                   ET2 = 1;
                   L1 = 0;
                                   L2 = 0;
               }


        }
         while(STATE == stabak)
     {
         switch(STATE)
      {
         case 0:
      {
         BUFFER[0] = SECOND[0];
         BUFFER[1] = SECOND[1];
      }break;
      
      case 5:
      {
          BUFFER[0] = CLOCK[2];
          BUFFER[1] = 101;/*A-*/
      }break;
      
      case 6:
      {
          BUFFER[0] = 110;/*A-*/
          BUFFER[1] = CLOCK[3];
      }break;
      
      default:
      {
          BUFFER[0] = CLOCK[2];
          BUFFER[1] = CLOCK[3];
      }break;

 

 

 

 

 


助工
2015-01-07 14:23:53     打赏
4楼

3、吴鉴鹰单片机实战项目精讲(连载)之摇摇棒的制作(一)——硬件介绍

 

相关原理图点击下载:

吴鉴鹰摇摇棒原理图.pdf

 

 

鉴鹰的摇摇棒具有如下功能:
   1) 显示  “就要离开电子科技大学了!”;
   2) 显示  “o(∩_∩)o”微笑图案;
   3) 显示    心形图案;
   4) 显示  “LOVE”;
   5) 显示  “天天开心”
   6)显示  “笑笑照顾好自己!”
   7)显示   “我们毕业了!”
   8)显示   “周晓晓”
   9) 可以通过开关实现转换,轮流显示并循环。

 

 


跟大家讲,摇摇棒其实很简单,大学期间,我自己用万用板搭了一个,别人觉得很好玩,就来问我怎么做。其实就是一个循环的LED显示,利用人的视觉滞留产生静态显示的现象。要实现这个目标,就要求延时部分做的比较小,所以采用石英晶体振荡器。而目前能够实现这种功能的器件有很多种,不同的类型的器件也能够很好的完成。

    鹰哥的这个作品本着方便、价格低廉的原则,采用单片机控制,由水银开关的闭合对单片机产生外部中断,从而对中断进行采集。到达一定数量便进行图象的转换。

 


   这是鹰哥当年在大学做的送给女朋友的哦!她玩了好久,还带回去给她老爸看了,所以年轻的工程师可以做一个送给你心爱的姑娘啊!信鉴鹰,搞定女神不是梦!

   整个系统由单片机控制模块,开关及电源模块和输出显示模块三个部分构成。


2、主要部件原理
   (1)单片机控制模块
    用单片机想要控制LED显示只需要定时输出就可以,但每个人摇动的速度不一样,如何准确的并稳定的变换图案呢?这就需要用到外部中断。将水银开关的两个引脚一端接VCC,一端接GND,这样的话,当摇棒向一边运动时LED按照程序编辑好的规律显示,而向另一边运动时LED全灭,此时一个周期就会产生一个下跳沿的信号,信号传递给单片机的nINT0产生中断,对中断的数量计数,当计到10时便转换显示的图案,当依次显示完后便回到初始状态进行循环。
由于人的视觉滞留时间长达0.1s,所以在每显示完一列LED后加入一段合适的延时,如5ms,每个字之间加入延时如15ms,这样,我们就能看到静态的稳定的字,并且每个字之间是有空隙的。为了让字能够在空间的中部显示,在启动中断显示后延时一段合适的时间,使棒在半圆轨迹的大约1/4处开始显示,这样看到的字方向上才比较正。
   
  (2)水银开关
水银开关,又称倾侧开关,是电路开关的一种,以一接著电极的小巧容器储存著一小滴水银,容器中多数注入惰性气体或真空。
   
  仔细观察水银开关,实际上他是一个封闭的玻璃管,里面有两个分开着的导线和一段水银球,当玻璃管的平衡位置变化时,水银球会来回移动,当水银球移动到两根导线时,因水银是金属-导体,故电路变为通路,此时接收器处于工作状态;反之,水银球远离两根导线时为断路,此时接收器处于非工作状态。
本设计采用震动开关代替水银开关,试验测试发现,水银开关多次高频率的接通断开后触点会氧化,容易接触不良,因此改用下面的震动开关。

 

 
   主要的人原理和器件鹰哥已经介绍完毕了,现在来给大家介绍大家最关心的程序了,让鹰哥来一点点介绍。


 


助工
2015-01-07 14:28:41     打赏
5楼

4、吴鉴鹰单片机实战项目精讲(连载)之摇摇棒的制作(二)——源程序介绍

/******************************************************
*程序:摇摇棒的设计程序                                                      
** 这一讲的主要内容: 吴鉴鹰摇摇棒的设计和制作                                                                                  
** 功能描述:  
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
#include <AT89X52.h>
#define uchar unsigned char
#define uint unsigned int    //宏定义
#define KEY P3_7      //定义画面切换按键
uchar KY;    //KY作用在后面说明     
uchar disp;     //显示汉字指针
uchar pic=0,num=0;     //pic为按键次数;num为中断次数

uchar code love[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x3F,0x00,0x20,0x00,0x20,0x00,0x20,
0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x0F,
0x04,0x10,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x04,0x10,0xF8,0x0F,0x00,0x00,
0x00,0x00,0x00,0x00,0xFE,0x07,0x00,0x08,0x00,0x10,0x00,0x20,0x00,0x20,0x00,0x10,
0x00,0x08,0xFE,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x3F,0x82,0x20,0x82,0x20,
0x82,0x20,0x82,0x20,0x82,0x20,0x82,0x20,0x82,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*LOVE*/
};

uchar code loveyou[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x78,0x00,0xFC,0x00,0xFE,0x01,0xFE,0x03,0xFE,0x07,0xFE,0x0F,0xFE,0x1F,0xFC,0x3F,
0xF8,0x7F,0xFC,0x3F,0xFE,0x1F,0xFE,0x0F,0xFE,0x07,0xFE,0x03,0xFE,0x01,0xFC,0x00,
0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*心形图案*/
};
uchar code hehe[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x01,0x40,0x01,0xC0,0x01,0x00,0x00,0x00,0x00,
0xF0,0x0F,0x08,0x10,0x04,0x20,0x00,0x00,0x00,0x00,0xF0,0x3F,0x08,0x00,0x04,0x00,
0x04,0x00,0x04,0x00,0x08,0x00,0xF0,0x3F,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x20,
0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x00,0x00,0x00,0xF0,0x3F,0x08,0x00,0x04,0x00,
0x04,0x00,0x04,0x00,0x08,0x00,0xF0,0x3F,0x00,0x00,0x00,0x00,0x04,0x20,0x08,0x10,
0xF0,0x0F,0x00,0x00,0x00,0x00,0xC0,0x01,0x40,0x01,0xC0,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*呵呵o(∩_∩)o图案*/
};
unsigned char code hanzi[] = {
/*--  文字:  欢  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
//0x04,0x24,0x44,0x84,0x64,0x9C,0x40,0x30,0x0F,0xC8,0x08,0x08,0x28,0x18,0x00,0x00,
//0x10,0x08,0x06,0x01,0x82,0x4C,0x20,0x18,0x06,0x01,0x06,0x18,0x20,0x40,0x80,0x00,

/*--  文字:  迎  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
//0x40,0x40,0x42,0xCC,0x00,0x00,0xFC,0x04,0x02,0x00,0xFC,0x04,0x04,0xFC,0x00,0x00,
//0x00,0x40,0x20,0x1F,0x20,0x40,0x4F,0x44,0x42,0x40,0x7F,0x42,0x44,0x43,0x40,0x00,

/*--  文字:  使  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
//0x80,0x60,0xF8,0x07,0x04,0xE4,0x24,0x24,0x24,0xFF,0x24,0x24,0x24,0xE4,0x04,0x00,
//0x00,0x00,0xFF,0x00,0x80,0x81,0x45,0x29,0x11,0x2F,0x41,0x41,0x81,0x81,0x80,0x00,

/*--  文字:  用  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
//0x00,0x00,0xFE,0x22,0x22,0x22,0x22,0xFE,0x22,0x22,0x22,0x22,0xFE,0x00,0x00,0x00,
//0x80,0x60,0x1F,0x02,0x02,0x02,0x02,0x7F,0x02,0x02,0x42,0x82,0x7F,0x00,0x00,0x00,

/*--  文字:  吴  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
//0x00,0x00,0x80,0x9E,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x9E,0x80,0x00,0x00,0x00,
//0x84,0x84,0x44,0x44,0x24,0x14,0x0C,0x07,0x0C,0x14,0x24,0x44,0x44,0x84,0x84,0x00,

/*--  文字:  鉴  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
//0x00,0x00,0x3E,0x00,0x80,0xBF,0x40,0x20,0x58,0x87,0x84,0x0C,0x34,0x04,0x00,0x00,
//0x02,0x42,0x49,0x49,0x5A,0x6A,0x4A,0x7E,0x4A,0x6A,0x5A,0x49,0x49,0x42,0x02,0x00,

/*--  文字:  鹰  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
//0x00,0x00,0xFE,0x22,0x12,0xFA,0x26,0x12,0xFB,0xAE,0xAA,0xFE,0xAA,0xAA,0x02,0x00,
//0x40,0x30,0x0F,0x40,0x40,0x5E,0x52,0x53,0x56,0x52,0x1A,0x56,0x90,0x70,0x00,0x00,

/*--  文字:  的  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
//0x00,0xF8,0x0C,0x0B,0x08,0x08,0xF8,0x40,0x30,0x8F,0x08,0x08,0x08,0xF8,0x00,0x00,
//0x00,0x7F,0x21,0x21,0x21,0x21,0x7F,0x00,0x00,0x00,0x43,0x80,0x40,0x3F,0x00,0x00,

/*--  文字:  摇  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
//0x10,0x10,0x10,0xFF,0x90,0x00,0x94,0x64,0x44,0x54,0xE2,0x42,0x63,0x5A,0x00,0x00,
//0x02,0x42,0x81,0x7F,0x00,0x00,0x02,0x7A,0x42,0x42,0x7F,0x42,0x42,0xFA,0x02,0x00,

/*--  文字:  摇  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
//0x10,0x10,0x10,0xFF,0x90,0x00,0x94,0x64,0x44,0x54,0xE2,0x42,0x63,0x5A,0x00,0x00,
//0x02,0x42,0x81,0x7F,0x00,0x00,0x02,0x7A,0x42,0x42,0x7F,0x42,0x42,0xFA,0x02,0x00,

/*--  文字:  棒  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
//0x10,0x10,0xD0,0xFF,0x90,0x10,0x44,0x54,0xD4,0x74,0x5F,0x54,0xD4,0x54,0x44,0x00,
//0x04,0x03,0x00,0xFF,0x00,0x01,0x12,0x11,0x14,0x14,0xFF,0x14,0x14,0x11,0x12,0x00,
    //就
0x04,0x10,0xE4,0x4B,0x25,0x82,0x26,0x7E,0x24,0x02,0xE4,0x0B,0x04,0x90,0x20,0x6,
0x20,0x1C,0xFF,0x03,0x20,0x00,0xE2,0x3F,0x2C,0x40,0x20,0x40,0x20,0x70,0x00,0x00,/*"就",0*/
/* (16 X 16 , 宋体 ) */
0x00,0x00,0x02,0x02,0xF2,0x82,0x92,0x92,0x92,0x9A,0xFE,0x56,0x92,0x63,0x92,0x22,
0x92,0x32,0xFE,0x4A,0x92,0x46,0x92,0x42,0xF2,0x82,0x02,0x02,0x00,0x00,0x00,0x00,/*"要",1*/
/* (16 X 16 , 宋体 ) */
0x04,0x00,0x04,0xFE,0x04,0x02,0xF4,0x02,0x84,0x12,0xD4,0x3A,0xA5,0x16,0xA6,0x13,
0xA4,0x12,0xD4,0x1A,0x84,0x32,0xF4,0x42,0x04,0x82,0x04,0x7E,0x04,0x00,0x00,0x00,/*"离",2*/
/* (16 X 16 , 宋体 ) */
0x80,0x00,0x82,0x80,0x82,0x40,0x82,0x30,0xFE,0x0F,0x82,0x00,0x82,0x00,0x82,0x00,
0x82,0x00,0x82,0x00,0xFE,0xFF,0x82,0x00,0x82,0x00,0x82,0x00,0x80,0x00,0x00,0x00,/*"开",3*/
/* (16 X 16 , 宋体 ) */
0x80,0x00,0x90,0x80,0x8C,0x80,0x84,0x84,0x84,0x46,0x84,0x49,0xF5,0x28,0x86,0x10,
0x84,0x10,0x84,0x2C,0x84,0x23,0x84,0x40,0x94,0x80,0x8C,0x00,0x80,0x00,0x00,0x00,/*"安",4*/
/* (16 X 16 , 宋体 ) */
0x10,0x01,0x88,0x00,0xC4,0xFF,0x23,0x48,0xAE,0x29,0x68,0x8D,0x2F,0xFB,0x28,0x09,
0xAE,0xAC,0x20,0x48,0xD8,0x37,0x17,0x08,0x10,0x36,0xF0,0x41,0x10,0x80,0x00,0x00,/*"徽",5*/
/* (16 X 16 , 宋体 ) */
0x04,0x20,0x84,0x60,0x84,0x20,0xFC,0x1F,0x84,0x10,0x84,0x10,0x00,0x40,0xFE,0x44,
0x92,0x44,0x92,0x44,0xFE,0x7F,0x92,0x44,0x92,0x44,0xFE,0x44,0x00,0x40,0x00,0x00,/*"理",6*/
/* (16 X 16 , 宋体 ) */
0x00,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0xFC,0x3F,
0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x04,0x20,0x00,0x20,0x00,0x00,/*"工",7*/
/* (16 X 16 , 宋体 ) */
0x20,0x80,0x20,0x80,0x20,0x40,0x20,0x20,0x20,0x10,0x20,0x0C,0x20,0x03,0xFF,0x00,
0x20,0x03,0x20,0x0C,0x20,0x10,0x20,0x20,0x20,0x40,0x20,0x80,0x20,0x80,0x00,0x00,/*"大",8*/
/* (16 X 16 , 宋体 ) */
0x40,0x04,0x30,0x04,0x11,0x04,0x96,0x04,0x90,0x04,0x90,0x44,0x91,0x84,0x96,0x7,
0x90,0x06,0x90,0x05,0x98,0x04,0x14,0x04,0x13,0x04,0x50,0x04,0x30,0x04,0x00,0x00,/*"学",9*/
/* (16 X 16 , 宋体 ) */
0x00,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x40,0x02,0x80,0xE2,0x7F,
0x22,0x00,0x12,0x00,0x0A,0x00,0x06,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"了",10*/
/* (16 X 16 , 宋体 ) */
       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
       0x00,0x00,0x00,0x00,0x7C,0x10,0xFE,0x3B,
       0xFE,0x3B,0x7C,0x10,0x00,0x00,0x00,0x00,
       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
unsigned char code  dayday[] = {
0x40,0x80,0x40,0x80,0x42,0x40,0x42,0x20,0x42,0x10,0x42,0x0C,0x42,0x03,0xFE,0x00,
0x42,0x03,0x42,0x0C,0x42,0x10,0x42,0x20,0x42,0x40,0x40,0x80,0x40,0x80,0x00,0x00,/*"天",0*/
/* (16 X 16 , 宋体 ) */
0x40,0x80,0x40,0x80,0x42,0x40,0x42,0x20,0x42,0x10,0x42,0x0C,0x42,0x03,0xFE,0x00,
0x42,0x03,0x42,0x0C,0x42,0x10,0x42,0x20,0x42,0x40,0x40,0x80,0x40,0x80,0x00,0x00,/*"天",1*/
/* (16 X 16 , 宋体 ) */
0x80,0x00,0x82,0x80,0x82,0x40,0x82,0x30,0xFE,0x0F,0x82,0x00,0x82,0x00,0x82,0x00,
0x82,0x00,0x82,0x00,0xFE,0xFF,0x82,0x00,0x82,0x00,0x82,0x00,0x80,0x00,0x00,0x00,/*"开",2*/
/* (16 X 16 , 宋体 ) */
0x00,0x10,0x00,0x0C,0x80,0x03,0x00,0x00,0x00,0x00,0xE0,0x3F,0x02,0x40,0x04,0x40,
0x18,0x40,0x00,0x40,0x00,0x40,0x00,0x78,0x40,0x00,0x80,0x01,0x00,0x0E,0x00,0x00,/*"心",3*/
/* (16 X 16 , 宋体 ) */
};
unsigned char code damogu[] = {
0x20,0x80,0x20,0x80,0x20,0x40,0x20,0x20,0x20,0x10,0x20,0x0C,0x20,0x03,0xFF,0x00,
0x20,0x03,0x20,0x0C,0x20,0x10,0x20,0x20,0x20,0x40,0x20,0x80,0x20,0x80,0x00,0x00,/*"大",0*/
/* (16 X 16 , 宋体 ) */
0x10,0x04,0x60,0x04,0x02,0x7C,0x0C,0x03,0xC0,0x80,0x04,0x88,0xE4,0x4B,0xAF,0x2A,
0xA4,0x1A,0xA4,0x0E,0xA4,0x1A,0xAF,0x2A,0xE4,0x4B,0x04,0x88,0x00,0x80,0x00,0x00,/*"漠",1*/
/* (16 X 16 , 宋体 ) */
0x02,0x42,0x02,0x82,0xF2,0x7F,0x8A,0x00,0x46,0x80,0x00,0x60,0xFC,0x1F,0x04,0x00,
0xFC,0x7F,0x04,0x28,0x02,0x10,0xFE,0x61,0x03,0x0E,0x02,0x30,0x00,0x40,0x00,0x00,/*"孤",2*/
/* (16 X 16 , 宋体 ) */
0x00,0x40,0x00,0x30,0xFE,0x0F,0x22,0x40,0x12,0x40,0xFA,0x5E,0x26,0x52,0x12,0x53,
0xFB,0x56,0xAE,0x52,0xAA,0x1A,0xFE,0x56,0xAA,0x90,0xAA,0x70,0x02,0x00,0x00,0x00,/*"鹰",3*/
/* (16 X 16 , 宋体 ) */
};
unsigned char code womenbiye[] = {
0x20,0x00,0x24,0x08,0x24,0x48,0x24,0x84,0xFE,0x7F,0x23,0x02,0x22,0x41,0x20,0x40,
0x20,0x20,0xFF,0x13,0x20,0x0C,0x22,0x14,0x2C,0x22,0xA0,0x41,0x20,0xF8,0x00,0x00,/*"我",0*/
/* (16 X 16 , 宋体 ) */
0x00,0x01,0x80,0x00,0x60,0x00,0xF8,0xFF,0x07,0x00,0x00,0x00,0xF8,0xFF,0x01,0x00,
0x06,0x00,0x00,0x00,0x04,0x00,0x04,0x40,0x04,0x80,0xFC,0x7F,0x00,0x00,0x00,0x00,/*"们",1*/
/* (16 X 16 , 宋体 ) */
0x00,0x04,0x00,0x04,0xFF,0x05,0x88,0x04,0x88,0x04,0x48,0x04,0x48,0x04,0x00,0xFF,
0x7F,0x04,0x88,0x04,0x84,0x04,0x84,0x04,0x82,0x04,0xE0,0x04,0x00,0x04,0x00,0x00,/*"毕",2*/
/* (16 X 16 , 宋体 ) */
0x00,0x40,0x10,0x40,0x60,0x40,0x80,0x43,0x00,0x40,0xFF,0x7F,0x00,0x40,0x00,0x40,
0x00,0x40,0xFF,0x7F,0x00,0x42,0x00,0x41,0xC0,0x40,0x30,0x40,0x00,0x40,0x00,0x00,/*"业",3*/
/* (16 X 16 , 宋体 ) */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0xFC,0x0F,0x04,0x04,0xFC,0x0F,0x00,0x00,0x10,0x44,0x10,0x82,0xFF,0x7F,
0x90,0x00,0xC8,0x40,0x09,0x4F,0x0E,0x60,0x08,0x5C,0xE8,0x43,0x08,0x40,0x00,0x00,/*"啦",4*/
/* (16 X 16 , 宋体 ) */
0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"!",5*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/* (16 X 16 , 宋体 ) */

};
unsigned char code  LiuShiShi[] = {
/*--  文字:  刘  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
0x08,0x28,0x48,0x89,0x0E,0x88,0x78,0x08,0x08,0x00,0xF8,0x00,0x00,0xFF,0x00,0x00,
0x40,0x20,0x10,0x09,0x06,0x19,0x60,0x00,0x00,0x00,0x0F,0x40,0x80,0x7F,0x00,0x00,

/*--  文字:  诗  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
0x40,0x40,0x42,0xCC,0x00,0x40,0x48,0x48,0x48,0x7F,0x48,0xC8,0x48,0x48,0x40,0x00,
0x00,0x00,0x00,0x7F,0x20,0x12,0x0A,0x32,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x00,

/*--  文字:  诗  --*/
/*--  楷体_GB231212;  此字体下对应的点阵为:宽x高=16x16   --*/
0x40,0x40,0x42,0xCC,0x00,0x40,0x48,0x48,0x48,0x7F,0x48,0xC8,0x48,0x48,0x40,0x00,
0x00,0x00,0x00,0x7F,0x20,0x12,0x0A,0x32,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x00,

};
unsigned char code Ytzgzj[] = {
{0x00,0x08,0x00,0x04,0x00,0x03,0xE0,0x00,0x00,0x00,0x00,0x40,0x00,0x80,0xFF,0x7F},
{0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x40,0x00,0x80,0x01,0x00,0x0E,0x00,0x00},/*"小",0*/
/* (16 X 16 , 宋体 ) */

0x40,0x00,0x40,0x00,0x42,0x00,0xCC,0x7F,0x00,0x20,0x40,0x12,0x48,0x0A,0x48,0x32,
0x48,0x02,0x7F,0x42,0x48,0x82,0xC8,0x7F,0x48,0x02,0x48,0x02,0x40,0x02,0x00,0x00,/*"诗",1*/
/* (16 X 16 , 宋体 ) */

0x00,0x80,0xFE,0x6F,0x42,0x08,0x42,0x08,0x42,0x28,0xFE,0xCF,0x00,0x00,0x42,0x00,
0xA2,0x2F,0x9E,0xC8,0x82,0x08,0xA2,0x08,0xC2,0x28,0xBE,0xCF,0x00,0x00,0x00,0x00,/*"照",2*/
/* (16 X 16 , 宋体 ) */

0x00,0x80,0xFE,0x7F,0x02,0x00,0xF2,0x7F,0x12,0x21,0x12,0x12,0xF2,0x89,0x00,0x80,
0xF2,0x4F,0x1A,0x20,0x16,0x18,0xD2,0x17,0x12,0x20,0xF2,0x4F,0x02,0x80,0x00,0x00,/*"顾",3*/
/* (16 X 16 , 宋体 ) */

0x10,0x40,0x10,0x22,0xF0,0x15,0x1F,0x08,0x10,0x16,0xF0,0x61,0x00,0x00,0x80,0x00,
0x82,0x40,0x82,0x80,0xE2,0x7F,0x92,0x00,0x8A,0x00,0x86,0x00,0x80,0x00,0x00,0x00,/*"好",4*/
/* (16 X 16 , 宋体 ) */

0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xFF,0x88,0x44,0x8C,0x44,0x8A,0x44,0x89,0x44,
0x88,0x44,0x88,0x44,0x88,0x44,0xF8,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"自",5*/
/* (16 X 16 , 宋体 ) */

0x00,0x00,0x00,0x00,0x82,0x3F,0x82,0x40,0x82,0x40,0x82,0x40,0x82,0x40,0x82,0x40,
0x82,0x40,0x82,0x40,0x82,0x40,0xFE,0x40,0x00,0x40,0x00,0x78,0x00,0x00,0x00,0x00,/*"己",6*/
/* (16 X 16 , 宋体 ) */

0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"!",7*/
/* (16 X 16 , 宋体 ) */

};
/*****函数声明*****/
void display1_ltor(void);
void display2_ltor(void);
void display2_rtol(void);
void display3(void);
void display4(void);
void display5(void);
void display6(void);
void display7(void);
void display8(void);
void display9(void);


/******************************************************
*程序:void DelayUs(uint N)                                                                                                                         
** 功能描述: n(us)延时子程序
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
void DelayUs(uint N)
{
uint x;
for(x=0; x<=N;x++);
}

/******************************************************
*程序:void intersvr0(void) interrupt 0                                                                                                                          
** 功能描述: 中断服务程序
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
void intersvr0(void) interrupt 0 
{
//;
KY=~KY;      //每个摇动来回水银开关会在摆幅两端分别产生下降沿中断,只提取其中一次(从左向右摇才显示)
if(KY==0)
{
    num++;     //计算中断次数
   switch(pic)      //选择画面
   {
     case 0:{display1_ltor();}break;
     case 1:{display2_ltor();}break;
     case 2:{display3();}break;
     case 3:{display4();}break;
case 4:{display5();}break;
case 5:{display6();}break;
case 6:{display7();}break;
case 7:{display8();}break;
case 8:{display9();}break;
     default:{display1_ltor();}  
    }
}
}

/******************************************************
*程序:void display1_ltor(void)                                                                                                                          
** 功能描述: 显示子程序1(汉字)
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
void display1_ltor(void)
{
uchar i;
if(num>10){disp++;num=0;}     //12个汉字分为3次显示完(每次显示4个),每中断10次切换
if(disp>2)disp=0;
   DelayUs(5200);     //此处延时时间依各硬件差别而各不相同,试着调整使得显示内容居中即可
for(i=0;i<64;i++)
{
      P0=~hanzi[disp*128+i*2];
      P2=~hanzi[disp*128+i*2+1];
      DelayUs(100);
}
}

/******************************************************
*程序:void display2_ltor(void)                                                                                                                          
** 功能描述: 显示子程序2(LOVE)
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
void display2_ltor(void)
{
uchar i;
DelayUs(4000);
for(i=0;i<64;i++) 
{
      P0=~love[i*2];
      P2=~love[i*2+1];
      DelayUs(140);
}
}

/******************************************************
*程序:void display3(void)                                                                                                                         
** 功能描述: 显示子程序3(心形图案)
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
void display3(void)
{
uchar i;
   DelayUs(4000);
for(i=0;i<64;i++)
{
      P0=~loveyou[i*2];
      P2=~loveyou[i*2+1];
      DelayUs(120);
}
}

/******************************************************
*程序:void display4(void)                                                                                                                         
** 功能描述: 显示子程序4(呵呵o(∩_∩)o图案)
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
void display4(void)
{
uchar i;
DelayUs(4000);
for(i=0;i<64;i++)
{
      P0=~hehe[i*2];
      P2=~hehe[i*2+1];
      DelayUs(120);
}
}

/******************************************************
*程序:void display5(void)                                                                                                                         
** 功能描述: 显示子程序5(天天开心)
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
void display5(void)
{
uchar i;
DelayUs(4000);
for(i=0;i<64;i++)
{
      P0=~dayday[i*2];
      P2=~dayday[i*2+1];
      DelayUs(120);
}
}

/******************************************************
*程序:void display6(void)                                                                                                                         
** 功能描述: 显示子程序6(天天开心)
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
void display6(void)
{
uchar i;
DelayUs(4000);
for(i=0;i<64;i++)
{
      P0=~damogu[i*2];
      P2=~damogu[i*2+1];
      DelayUs(120);
}
}

/******************************************************
*程序:void display7(void)                                                                                                                        
** 功能描述: 显示子程序7(天天开心)
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
void display7(void)
{
uchar i;
if(num>10){disp++;num=0;}     //8个汉字分为3次显示完(每次显示4个),每中断10次切换
if(disp>1)disp=0;
   DelayUs(5200);     //此处延时时间依各硬件差别而各不相同,试着调整使得显示内容居中即可
for(i=0;i<64;i++)
{
      P0=~womenbiye[disp*128+i*2];
      P2=~womenbiye[disp*128+i*2+1];
      DelayUs(100);
}
}

/******************************************************
*程序:void display8(void)                                                                                                                         
** 功能描述: 显示子程序8(天天开心)
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
void display8(void)
{
uchar i;
DelayUs(4000);
for(i=0;i<64;i++)
{
      P0=~LiuShiShi[i*2];
      P2=~LiuShiShi[i*2+1];
      DelayUs(120);
}   
}

/******************************************************
*程序:void display9(void)                                                                                                                         
** 功能描述: 小诗照顾好自己
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
void display9(void)
{
uchar i;
if(num>10){disp++;num=0;}     //8个汉字分为2次显示完(每次显示4个),每中断10次切换
if(disp>1)disp=0;
   DelayUs(5200);     //此处延时时间依各硬件差别而各不相同,试着调整使得显示内容居中即可
for(i=0;i<64;i++)
{
      P0=~Ytzgzj[disp*128+i*2];
      P2=~Ytzgzj[disp*128+i*2+1];
      DelayUs(100);
} 
}

/******************************************************
*程序:void main(void)                                                                                                                         
** 功能描述: 主函数
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
void main(void)
{
IT0=1;
EX0=1;
EA=1;      //开中断,下降沿中断
KY=0;
KEY=1;
while(1)     //主程序中只检测按键
{
   if(KEY==0)     //画面切换键按下
  {
      DelayUs(10000);     //按键去抖
     if(KEY==0) //这个地方多了一个分号,谢谢 lhxtzlhxtz的提醒!这是我的疏忽,向大家道歉,只能以后发表更多有价值的帖子表示我的歉意了!
     pic++;
      while(KEY==0);
   }
   if(pic>8)pic=0;
}
}
/*****END*****/

 

 


助工
2015-01-08 09:07:31     打赏
6楼

5、吴鉴鹰单片机项目详细解析系列连载之基于单片机的电子秤设计(一)——硬件原理介绍

 

 原理图请点击下载:吴鉴鹰基于单片机的电子秤设计原理图.pdf

 

 

   有读者有疑问,怎么吴鉴鹰介绍的都是硬件和软件的结合,而且内容还讲的那么细,觉得很罗嗦,亲们不要急,在以后的章节中,一些现在工业常用的项目技巧我会逐步与大家分享,到时候可能针对某些特定的知识点单独分享!谢谢亲们的支持和理解!

   今天,吴鉴鹰来给大家讲述第四讲,就是日常生活中很常见的电子秤的设计,这个东西貌似很简单,其实要做一个稳定性高,精度高的电子秤也不是一个简单的事情。

首先鹰哥来给电子秤的做个简单的介绍: 

 1

   电子称是什么,讲的专业点就是:利用物体的重力作用来确定物体质量的测量仪器,也可用来确定与物体质量相关的其他量的大小,参数,或特性

用我们自己话讲就是测重量的。

 

 2

   电子称一般由以下三部分组成。承重、传力复位系统,称重传感器,测量显示和数据输出的的载荷测量装置。当被称物体放置在秤体的秤台上时,其重量便通过秤体传递到称重传感器,传感器随之产生力-电效应,将物体的重量转换成与被称物体重量成一定函数关系(一般成正比关系)的电信号(电压或电流等)。此信号由放大电路进行放大、经滤波后再由模/数(A/D)器进行转换,数字信号再送到微处器的CPU处理,CPU不断扫描键盘和各种功能开关,根据键盘输入内容和各种功能开关的状态进行必要的判断、分析、由仪表的软件来控制各种运算。运算结果送到内存贮器,需要显示时,CPU发出指令,从内存贮器中读出送到显示器显示,我们这里显示采用是12864,其实真实显示应该不会用这个,鹰哥在这里主要是跟大家分享12864驱动程序的编写。一般地信号的放大、滤波、A/D转换以及信号各种运算处理都在仪表中完成。

 3

  电子秤介绍鹰哥就介绍到这了,下面开始硬件部分的介绍了

   首先,鹰哥给大家从该设计的最前端讲起了,先是信号的采集,在这里就是所测得物体的重量,将物体的重量转化成我们MCU能测量的电压信号。

  

   本设计采用SP20C-G501电阻应变式传感器,其最大量程为7.5 Kg.称重传感器由组合式S型梁结构及金属箔式应变计构成,具有过载保护装置。由于惠斯登电桥具诸如抑制温度变化的影响,抑制干扰,补偿方便等优点,所以该传感器测量精度高、温度特性好、工作稳定等优点,广泛用于各种结构的动、静态测量及各种电子秤的一次仪表。该称重传感器主要由弹性体、电阻应变片电缆线等组成,其工作原理如图所示





 5

传感器工作原理

    其工作原理:用应变片测量时,将其粘贴在弹性体上。当弹性体受力变形时,应变片的的敏感栅也随之变形,其阻值发生相应的变化,通过转换电路转换为电压或电流的变化。由于内部线路采用惠更斯电桥,当弹性体承受载荷产生变形时,输出信

号电压可由下式所示:

    Eout = R2R4×(ΔR1/R1+ΔR2/R2+ΔR3/R3+ΔR4/R4)/(R2+R4) (这是传感器的知识,感兴趣可以找下相关的资料)

放大电路介绍:

   主要由高精度低漂移运算放大器构成差动放大器,而构成的前级处理电路差动放大器具有高输入阻抗,增益高的特点,可以利用普通运放做成一个差动放大器。

    一般说来,集成化仪用放大器具有很高的共模抑制比和输入阻抗,因而在传统的电路设计中都是把集成化仪器放人器作为前置放人器。然而,绝人多数的集成化仪器放大器,特别是集成化仪器放大器,它们的共模抑制比与增益相关:增益越高,共模抑制比越大。而集成化仪器放大器作为心电前置放大器时,由于极化电压的存在,前置放大器的增益只能在几十倍以内,这就使得集成化仪器放大器作为前置放大器时的共模抑制比不可能很高。有同事问过鹰哥试图在前置放大器的输入端加上隔直电容(高通网络)来避免极化电压使高增益的前置放大器进入饱和状态,但由于信号源的内阻高,且两输入端不平衡,隔直电容(高通网络)使等共模干扰转变为差模干扰,结果适得其反,严重地损害了放大器的性能。 

为了实现信号的放人,其设计电路如图所示:

                                     6

1. 前级采用运放AlA2组成并联型差动放大器。理论上不难证明,存运算放大器为理想的情况下,并联型差动放人器的输入阻抗为无穷人,共模抑制比也为无穷人。更值得一提的是,在理论上并联型差动放人器的共模抑制比与电路的外围电阻的精度和阻值无关。

2. 阻容耦合电路放存由并联型差动放大器构成的前级放大器和由仪器放大器构成的后级放大器之间,这样可为后级仪器放大器提高增益,进而提高电路的共模抑制比提供了条件。同时,南于前置放大器的输出阻抗很低,同时又采用共模驱动技术,避免了阻容耦合电路中的阻、容元件参数不对称(匹配)导致的共模干扰转换成差模干扰的情况发生。

3. 后级电路采用廉价的仪器放大器,将双端信号转换为单端信号输出。由于阻容耦合电路的隔直作用,后级的仪器放大器可以做到很高的增益,进而得到很高的共模抑制比。

                                                   7

可见康华光版的模电pg36页的介绍:VR1= V1 - V2VR1/R1 = (V3-V4)/(2R2+R1),顾得

V3-V4 = (2R2+R1)×VR1/R1 = (1+2R2/R1)×(V1-V2)

    由减法电路:VO =  R4(Vi2-Vi1)/R1,可得

       VO = -R4×(V3-V4)/R3= -R4×(1+2R2/R1)×(V1-V2)/R3

所以电路的电压增益为:

AV = VO/(V1-V2)=-R4×(1+2R2/R1)/R3

在鹰哥的这个设计里面,将数据代入得到:

AV = -20×(1+2×4)/10 = -18

AD采样模块:

    在检测系统中,传感器将采集到的信号(例如:我们这个项目中,信号就是瓦斯的浓度),这些信号都是模拟信号,将这些模拟信号进行处理,放大、滤波、补偿、以及信号的变换等方式,然后在案通过某些芯片将模拟信号变成数字信号,这里我们用ADC0809将传感器转化的电压进行数字化,然后再传递给MCU,也就是51单片机。一定会有人问我,为什么采用这么低档次的51单片机,精确度如此低的ADC0809,鹰哥告诉你,一个好的项目并不是采用的芯片越高档就越好,而且对于初学者,档次越低的芯片,学到的东西越多,所以大家不要嫌弃51单片机低级,也不要嫌弃ADC0809芯片不够先进。

   相信鹰哥,只要你能把ADC0809用好,别的AD转换芯片也没有问题。

鹰哥来给大家简单介绍一下ADC0809芯片。

 

 8

 

ADC0809芯片简单介绍

       当时鹰哥采用的是ADC0809是采样分辨率为8位的、以逐次逼近原理进行模—数转换的器件,。其内部有一个8通道多路开关,它可以根据地址码锁存译码后的信号,只选通8路模拟输入信号中的一个进行A/D转换。芯片的引脚图如图所示:

1、ADC0809芯片有28条引脚,采用双列直插式封装,如图所示。下面说明各引脚功能

      (1) IN0-IN7:8路模拟量输入端;

      (2) D0-D7:8位数字量输出端;

      (3) ADD-A、ADD-B、ADD-C:3位地址输入线,用于选通8路模拟输入中的一路;

      (4) ALE:地址锁存允许信号输入端,高电平有效;

      (5) START:A/D转换启动脉冲输入端,输入一个正脉冲(至少100ns宽)使其启动(脉冲上升沿使ADC0809复位,下降沿启动A/D转换);

      (6) EOC:A/D转换结束信号,输出,当A/D转换结束时,此端输出一个高电平(转换期间一直为低电平);

      (7) OE:数据输出允许信号,输入,高电平有效。当A/D转换结束时,此端输入一个高电平,才能打开输出三态门,输出数字量;

      (8) CLK:时钟脉冲输入端。要求时钟频率不高于640KHZ;

      (9) REF(+)、REF(-):基准电压;

      (10) Vcc:电源,单一+5V;

      (11) GND:接地。

2、ADC0809的主要特性有:

      (1) 8路输入通道,8位A/D转换器,即分辨率为8位;

      (2) 具有转换起停控制端;

      (3) 转换时间为100μs;

      (4) 单个+5V电源供电;

      (5) 模拟输入电压范围0~+5V,不需零点和满刻度校准;

      (6) 工作温度范围为-40~+85摄氏度;

      (7) 低功耗,约15mW。

3、ADC0809的工作过程:

      首先输入3位地址,并使ALE=1,将地址存入地址锁存器中。此地址经译码选通8路模拟输入之一到比较器。START上升沿将逐次逼近寄存器复位。下降沿启动 A/D转换,之后EOC输出信号变低,指示转换正在进行。直到A/D转换完成,EOC变为高电平,指示A/D转换结束,结果数据已存入锁存器,这个信号可用作中断申请。当OE输入高电平时,输出三态门打开,转换结果的数字量输出到数据总线上。

    对于AD采样的模块就到这了,后面内容更加精彩。

显示部分: 

本项目采用12864液晶屏显示,由于 IO口资源不够用,所以只能采用串口驱动,可以节约大量的IO口资源,不要说鹰哥是小气啊,其实是IO口不够。

 9

 

 

 10

这是实物图片,左边是用AT89C51做的,右侧和下面的是移植到C8051F020单片机上面的。

 

 

 11

 


                    图 12

人机界面:

由于电子秤需要设置单价(十个数字键),还具有确认、删除等功能,总共需设置17个键(包括一个复位键)。键盘的扩展有使用以下方案:

采用矩阵式键盘:矩阵式键盘的特点是把检测线分成两组,一组为行线,一组列线,按键放在行线和列线的交叉点上。图2-4给出了一个4×4的矩阵键盘结构的键盘接口电路,图中的每一个按键都通过不同的行线和列线与主机相连这。4×4矩阵式键盘共可以安装16个键,但只需要8条测试线。当键盘的数量大于8时,一般都采用矩阵式键盘。结合本设计的实际要求,16个按键使用4×4矩阵式键盘,另外四个键使用独立式按键实现。

 

 13


电源模块:

采用7805,790578127912组成稳压电路

   7805,7905固定式三端稳压器可输出±5V,固定式三端可调稳压器78127812组装电路可对称输出±12v,其电路图如图所示

由三端可调式稳压器和三端固定式稳压器共同组成,所用器件比方案一多,但电路组装简单,不会增添麻烦,在方案二中可直接得到+5v和±12的输出电压.

使用时比较方便。

 

 

 14

 

 


助工
2015-01-08 09:21:07     打赏
7楼
多谢版主的信任和支持,只能靠分享更多的原创经典帖子来报答了。

助工
2015-01-10 13:11:29     打赏
8楼

6、吴鉴鹰单片机项目详细解析系列连载之基于单片机的电子秤设计(二)——源代码设计介绍

 

/******************************************************
*程序:吴鉴鹰基于单片机的电子秤的设计程序                                                      
** 这一讲的主要内容: 电子称是什么,讲的专业点就是:
利用物体的重力作用来确定物体质量的测量仪器,也可用来确定与物体质量相关的其他量的大小,
参数,或特性用我们自己话讲就是测重量的。                                                                                  
** 功能描述:  
** 输 入:         
** 内容:     
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22

备注:有什么错误的地方,欢迎各大烧友指正

O(∩_∩)O~
*******************************************************/
#include <reg51.h>
#include <intrins.h>
#include<stdlib.h>
#include<math.h>                
#define uchar unsigned char  //宏的定义变量类型 uchar 代替 unsigned char
#define uint  unsigned int  //宏的定义变量类型 uint  代替 unsigned int
#define delay_time_max   50   //按键去抖动延时阀值
sbit    RS = P2^0;
sbit    RW = P2^1;
sbit    SCLK = P2^2;
sbit    LCDRST = P2^3;
sbit         ST=P3^6;                //启动信号
sbit         EOC=P3^3;                //转换结束信号,连到外部中断1口,转换结束后进入外部中断
sbit         OE=P3^7;                //输出使能
uchar          KEY_VALUE;
uchar          key_data;
uchar          dis_buf;            //显示缓存
uchar          temp;
uchar          key;                //键顺序码
uchar         result;
uint         f;
void delay(uchar x);      //x*0.14MS
// 此表为 LED 的字模              0   1  2  3    4  5  6  7  8  9   a    b    c d   e   f
unsigned char code LED7Code[] = {~0x3F,~0x06,~0x5B,~0x4F,~0x66,~0x6D,~0x7D,~0x07,~0x7F,~0x6F,~0x77,~0x7C,~0x39,~0x5E,~0x79,~0x71};
unsigned char  ADC0809[],KONGBVAI[],DANJIA[];
void ADC0809_change(); 


/*************************************************************************************
** 函数名称:  delayms
** 功能描述:  译码功能,将需要显示的数字转成相应的七段译码表
              如要显示的字符为“0”,则为7e ---0111 1111,就中间的一个LED不亮
** 输 入:    ms:需要延时的长度
**         
**        
** 输 出: 
**         
** 全局变量: 
** 调用模块: 
**
** 作 者:     吴鉴鹰
** 日 期:     14.02.22
**-----------------------------------------------------------------------------------
** 修改人:吴鉴鹰
** 日 期:
**----------------------------------------------------------------------------------
****************************************************************************************/
void delayms(uint ms)
{
        uchar i;
        while(ms--) for(i=0;i<120;i++);
}

/*********************************************************************************
** 函数名称:   SendByte  
** 功能描述:   串口给液晶发送数据  
                                                         
** 输 入:  Dbyte
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.02.28
************************************************************************************/
void SendByte(uchar Dbyte)
{
     uchar i;
     for(i=0;i<8;i++)
     {
           SCLK = 0;
           Dbyte=Dbyte<<1;      //左移一位
           RW = CY;            //移出的位给RW
           SCLK = 1;
           SCLK = 0;
     }
}
/***********************************************************************************
** 函数名称:   TransferCom  
** 功能描述:   串口给液晶发送命令  
                                                         
** 输 入:  data0
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.02.28
**********************************************************************************/
void    TransferCom(uchar data0)  
{
   RS=1;
   SendByte(0xf8);            //11111ABC,RW(0),RS(1),0
   SendByte(0xf0&data0);      //高四位
   SendByte(0xf0&data0<<4);   //低四位(先执行<<)
   RS=0;            
}
/*******************************************************************************
** 函数名称:   lcd_mesg  
** 功能描述:   写数据,
                                                          
** 输 入:  data1
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.02.28
*****************************************************************************/
void    TransferData(uchar data1)  
{
   RS=1;
   SendByte(0xfa);            //11111ABC,RW(0),RS(1),0
   SendByte(0xf0&data1);      //高四位
   SendByte(0xf0&data1<<4);   //低四位(先执行<<)
   RS=0;

}
/************************************************************************
** 功能描述:   12864初始化程序,为液晶屏的正常工作做准备 
                                                          
** 输 入: 
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.02.28
***********************************************************************/
void  initinal(void)           //LCD字库初始化程序
{
        delay(40);             //大于40MS的延时程序
        LCDRST=0;               //复位
        delay(1);              //延时
        LCDRST=1;                 //复位置高
        delay(10);
        TransferCom(0x30);  //Extended Function Set :8BIT设置,RE=0: basic instruction set, G=0 :graphic display OFF
        delay(100);            //大于100uS的延时程序
        TransferCom(0x0C);  //Display Control,D=1,显示开
        delay(100);            //大于100uS的延时程序
        TransferCom(0x01);  //Display Clear
        delay(10);             //大于10mS的延时程序
        TransferCom(0x06);  //Enry Mode Set,光标从右向左加1位移动
        delay(100);            //大于100uS的延时程序
}
/***********************************************************************
** 函数名称:   lcd_mesg  
** 功能描述:   汉字的显示,输入要显示汉字的地址,以及个数,已经要显示的字符的数组地址
                                                          
** 输 入: han,lie ,k ,*chn        
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.02.28
*************************************************************************/
void   lcd_mesg(uchar han,uchar lie,uchar k,uchar *chn)
{ 
        uchar i;
      switch(han)
        {
                case 1:TransferCom(0x80+lie);break;
                case 2:TransferCom(0x90+lie);break;
                case 3:TransferCom(0x88+lie);break;
                case 4:TransferCom(0x98+lie);break;
                default:;
        }
  
        delay(100);
        for(i=0;i<k;i++)
    {
        TransferData(chn);
    }
}
/***************************************************************************
** 函数名称:   JZkeyscan  (这里采用的是线反转法)
** 功能描述:   矩阵式键扫描子程序  (4*4 的矩阵) P1.4 P1.5 P1.6 P1.7为行   
                                                P1.3 P1.2 P1.1 P1.0为列 
     独立式按键扫描子程序(4个独立式按键) P2.4  P2.5 P2.6 P2.7          
** 输 入: 
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.02.28
*******************************************************************************/
uchar JZkeyscan(void)
{
   uchar sccode,recode,key_times,key_lock,JZ_FLAG;
   P1=0xf0;                                        //置所有列为低电平,列扫描,行线输入(此时)
   if((P1&0xf0) == 0xf0)                           
   {                                
   key_lock = 0;                                //如果在这个时候有个毛刺,在这个时候将标志位key_lock置为0
   key_times = 0;                              //将key_times置为0,这样可以有效的预防干扰,吴鉴鹰自己用过,效果很好
   JZ_FLAG = 0;                                 //取代纯延时的标志位,如果该标志位置为1,相当于原来的delay(0执行完成
   }                                           
   if(((P1&0xf0)!=0xf0)&&(key_lock == 0))            //判断是否有有键按下(读取列的真实状态,若第4列有键按下则P1的值会变成0111 0000),有往下执行
   {      
    if(key_times < delay_time_max)            //用这种方法代替过去的delay()延时去抖动
    {                                         //这样就不会在按键处理时影响干别的事情
             key_times++;                           //由于很多工业控制项目对时间的要求是很高的,是不允许   
    }                                         //纯延时的,所以吴鉴鹰采用这种方法解决这种问题
    else                                      //我也是工作后才意识到的,所以分享给大家
    {
       key_times = 0;                         //如果满足这个条件,表示相当于delay()延时完成了
    JZ_FLAG = 1;
    }
          if(((P1&0xf0)!=0xf0)&&(key_lock == 0)&&(JZ_FLAG == 1))    //再次判断列中是否是干扰信号,不是则向下执行
          {
              sccode=0xFE;                          //逐行扫描初值(即先扫描第1行) 
              while((sccode&0x10) != 0)             //行扫描完成时(即4行已经全部扫描完成)sccode为1110 1111停止while     
              {
                    P1=sccode;                      //输出行扫描码
                    if ((P1&0xf0) != 0xf0)          //本行有键按下(即P1(真实的状态)的高四位不全为1)
                    {
                           recode = (P1&0xf0)|0x0f; //输出列扫描码 按位或运算
                           JZ_FLAG = 0;             //将该变量置为1,防止反复进入
                                           key_lock = 1;            //将该变量置为1,防止反复进入
                           return(sccode&recode);   //返回行和列
                     }
                     else                           //所扫描的行没有键按下,则扫描下一行,直到4行都扫描,此时sccode值为1110 1111 退出while程序
                    {
                           sccode=(sccode<<1)|0x01;//行扫描码左移一位
                    }
               }
          }
           else
             {
               return 0;        //无键按下,返回0
          }
   }
}
/*****************************************************************************
** 函数名称:   DLkeyscan  (这里采用的是线反转法)
** 功能描述:   独立式按键扫描子程序(4个独立式按键) P2.4  P2.5 P2.6 P2.7 
              
** 输 入: 
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.02.28
******************************************************************************/
uchar  DLkeyscan()
{ 
    uchar DLkey_lock,DLkey_times,DL_FLAG,DL_VALUE;
    if((P2&0XF0) == 0XF0)
   {
     DLkey_lock = 0;                                   //如果在这个时候有个毛刺,在这个时候将标志位key_lock置为0
        DLkey_times = 0;                               //将DLkey_times置为0,这样可以有效的预防干扰,吴鉴鹰自己用过,效果很好 
        DL_FLAG = 0;                                //取代纯延时的标志位,如果该标志位置为1,相当于原来的delay(0执行完成
   }
    if((P2&0Xf0 != 0xf0)&&(DLkey_lock == 0))
   {
     if(DLkey_times < delay_time_max)                  //用这种方法代替过去的delay()延时去抖动
   {                                                 //这样就不会在按键处理时影响干别的事情
         DLkey_times++;
   }
   else
    {
       DLkey_times = 0;                             //如果满足这个条件,表示相当于delay()延时完成了
       DL_FLAG = 1;
    }
}
if(((P2&0Xf0) != 0xf0)&&(DL_FLAG == 1))                
{
    DL_VALUE = P2&0XF0;
    switch(DL_VALUE)
    {
         case 0x70: return  16;break;                   //通过检测P2口不同的值得到不同的按键值,进行不同的处理
             case 0xb0: return  17;break;
             case 0xd0: return  18;break;
             case 0xe0: return  19;break;
    }
    DL_FLAG = 0;                            //防止反复进入 
}
}
/*********************************************************************************
** 函数名称:   Delay  
** 功能描述:   纯延时函数
              
** 输 入:   MS  需要延时的时间         
** 输 出: num
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.02.28
***********************************************************************************/
void Delay(unsigned int MS)
{
         unsigned char us,usn;
         while(MS!=0)             //for 12M
         { 
   usn = 2;
            while(usn!=0)
   {
    us=0xf5;
    while (us!=0){us--;};
    usn--;
            }
                MS--;
        }
}
/*********************************************************************************
** 函数名称:   KEY_SACN_VALUE  
** 功能描述:   将按键测试程序得到的值转化成相应的键值
              
** 输 入: key_data
**         
**         
** 输 出: num
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.02.28
**********************************************************************************/
uchar  KEY_SACN_VALUE(key_data)
{
      switch(key_data)
   {
     case 0xee: KEY_VALUE=1;break;
     case 0xde: KEY_VALUE=2;break;
     case 0xbe: KEY_VALUE=3;break;
     case 0x7e: KEY_VALUE=4;break;
     case 0xed: KEY_VALUE=5;break;
     case 0xdd: KEY_VALUE=6;break;
     case 0xbd: KEY_VALUE=7;break;
     case 0x7d: KEY_VALUE=8;break;
     case 0xeb: KEY_VALUE=9;break;
     case 0xdb: KEY_VALUE=10;break;
     case 0xbb: KEY_VALUE=11;break;
     case 0x7b: KEY_VALUE=12;break;
     case 0xe7: KEY_VALUE=13;break;
     case 0xd7: KEY_VALUE=14;break;
     case 0xb7: KEY_VALUE=15;break;
     case 0x77: KEY_VALUE=16;break;
     default: break;
   }
   return KEY_VALUE;
   key_data = 0;
}
/************************************************************************************
** 函数名称:  show
** 功能描述:  显示函数,其中Fdata为状态为第一位,Sdata状态为第二位,Tdata为状态为第三位。
     Fdata为状态为第四位。degdata为显示的具体数值degdata 为4位  例如23.21(要求degdata输入格式)
** 输 入: Fdata  Sdata  Ddata  Hdata
**         
**        
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22
******************************************************************************/  //
void Data_change(uchar uidata)
{ 
   uchar AD_FLAG,i,data_calue;
   data_calue =  10*uidata;
   if(data_calue > 100)
   {
            ADC0809[2] = (uidata*10)/100;
            ADC0809[1] = (uidata*10)%100/10;
            ADC0809[0] = (uidata*10)%10;
   }
   else  if(data_calue > 10)
   {
       ADC0809[2] = 0;
       ADC0809[1] = (uidata*10)/10;
       ADC0809[0] = (uidata*10)%10;
   }
   else
   {
       ADC0809[2] = 0;
       ADC0809[1] = 0;
       ADC0809[0] = (uidata*10)%10;
   }
}
/***************************************************************************
** 函数名称:  ADC0809
** 功能描述:  ADC0809转换函数
     
** 输 入: 
**         
**        
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22
*******************************************************************************/
void ADC0809_change()
{
ST=0;       //启动A/D转换
ST=1;       //启动A/D转换
ST=0;  //启动A/D转换
while(EOC==0);  //等待转换完成
OE=1;
if(f==1)
{
  delayms(1000);                   // 延时1s
  lcd_mesg(1,1,3,ADC0809);       //液晶显示数据
}
else 
{                                     //这是鹰哥的风格,不管几句话都加上大括号,这样看起不会乱
     lcd_mesg(1,1,3,KONGBVAI);       //液晶显示数据   //如果初始化未成功则显示空白
}
//Display_Result(P3);
OE=0; 
}  

/*******************************************************************************
** 函数名称:   void main()  
** 功能描述:   主程序 
                                                          
** 输 入:  
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.02.28
*****************************************************************************/
void main()
{
    unsigned char i = 0,zongjia_Value,key_data,zongjia[8];
        unsigned char danjia[]= {"单价:"};
        unsigned char zongjia_led[] = {"总价:"};
    P0=0xFF;                    //置P0口
    P1=0xFF;                    //置P1口  
        TMOD=0x02;              //T1工作模式2
        TH0=0x14;                 //定时器初始值高位 
        TL0=0x00;
        IE=0x82;                 //IE.7位为1表示CPU开放中断,IE.1位也为1,表示允许定时器T0溢出中断 
        TR0=1;                     //使能定时器
        P1=0x00;              //选择ADC0809的通道1(000)(P1.0~P1.2) 
    delay(10);                  //延时
    initinal();                 //液晶的初始化函数

    while(1)
    { 
      key_data = JZkeyscan();
          if(key_data!=0)
          {
            KEY_SACN_VALUE(key_data);
          }
                  KEY_VALUE = DLkeyscan(); 
    
       if( i < 5)
       {
          DANJIA[i] = KEY_VALUE;
                     i++;
       }   
            else
           {
              i = 0;
           }
  if(KEY_VALUE == 13)
  {
     zongjia_Value = result*(DANJIA[4]*10000+DANJIA[3]*1000+DANJIA[2]*100+DANJIA[1]*10+DANJIA[0]);
     zongjia[7] = zongjia_Value/10000000;
     zongjia[6] = zongjia_Value%10000000/1000000;
     zongjia[5] = zongjia_Value%1000000/100000;
     zongjia[4] = zongjia_Value%100000/10000;
     zongjia[3] = zongjia_Value%10000/1000;
     zongjia[2] = zongjia_Value%1000/100;
     zongjia[1] = zongjia_Value%100/10;
     zongjia[0] = zongjia_Value%10;
     lcd_mesg(2,1,8,zongjia_led);
  }
     ADC0809_change();
    }
  }   

/******************************************************************************
** 函数名称:  counter1
** 功能描述:  当数据采集完毕,出发单片机的外部中断进行数据的存储显示以及报警
** 输 入: 
**         
**        
** 输 出: 
**         
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:     14.02.22
*******************************************************************************/
void  counter1(void) interrupt 2 using 2
{ 
   EX1=0;
   result = P0;
   EX1=1;
   Data_change(result);
}

 

 


助工
2015-01-10 13:53:19     打赏
9楼

7、吴鉴鹰单片机项目详细解析系列(连载)之基于单片机的微机键盘的运用 (一)——原理介绍

     有的时候我们总是抱怨键盘太少,做起来太麻烦了,所以就有人就比较聪明,直接运用电脑的键盘,也就是人们常说的“微机键盘”。下面吴鉴鹰就针对这个微机键盘的给大家做简单的介绍,已解决大家的键盘太少之忧,让大家做人机界面更加畅通无阻。

 

图 1

     本文通过分析微机键盘的工作原理及数据格式从单片机应用系统的实际需出发对微机键盘与单片机的接口及软件进行了设计。用中断方式实现了微机键盘与单片机之间的通信。

     大家知道微机键盘是微机系统必不可少的外设其品种很多既有最经常使用的101102 等键盘又有各种适用于金融、证券等领域的小键盘。实际上单片机应用系统中也可用微机键盘作为人机交互工具。然而由于微机键盘的数据格式较多要开发它的完整功能编程量大。因此,在实际使用中往往要求厂家做成适合于单片机应用接口要求的特殊键盘R S 2 32 串口格式这对应用是很不方便的。

    本文通过开发实践体会到微机键盘应用于单片机系统时只要满足实际要求硬件电路和软件设计完全可以简化并在这方面作了许多工作。

键盘功能及数据格式

键盘通过五芯插头与主机系统相连。一条数据线、一条时钟线均是双向的

(既可向系统发键盘数据又可接收系统发来的键盘命令), 一条是复位线另两条分别是+ SV 电源线和地线。五芯插头的布局如图所示。

 

图 2

微机键盘尽管形式各异但一般都符合两种标准川一种是Pc / XT 标准另一种是AT标准。前者数据位为(较老式), 后者数据是较常用的一种标准目前许多微机键盘都兼容这一标准。下面对后者作一简要介绍:                           

1.1 键盘功能

键盘通过数据线和时钟线与系统通信它接收系统发来的键盘命令码送出键盘数据。

在接通电源后键盘首先进行复位等初始化工作然后进行键盘扫描作好接收命令和发送键盘数据的准备工作。

键盘和系统相互间的数据通信均采用位格式的串行方式第一位起始位位是位数据位(低位在前高位在后), 10 位是奇偶校验位位是停止位数据的起始位为低电平。系统接收的键盘数据和键盘接收的键盘命令均在移位时钟的下降沿同步输人时钟周期为50 u s 。其时序如图所示。

微机键盘与系统通信帧格式时序

图 3 

1.2 键盘命令

键盘命令是由系统发送给键盘的命令码。键盘在接收到这些命令时20 ms 内予以响应即送回一个响应(FA ll)

键盘命令的含义如下:

(l) FFH 复位键盘一一使键盘进行复位和内部自测试操作;

(2FE H 重新发送一检测到键盘数据错误时要求键盘重新输出原来的内容;

(3) F6 H 设置键盘缺省值一一使键盘复位到初始状态并停止键盘扫描;

(4) FS H 设置缺省值并停止键盘一一使键盘复位到初始状态并停止键盘扫描;

(5) F4 H 启动键盘一一清除键盘输出缓冲器并启动键盘扫描和输出数据;

(6) F3 H 设置拍发速率延时参数;

(7) E E H 回响命令一一要求键盘接收到此命令时也回送E E H 予以响应;

(8) E l置位复位LE D 指示器。

1.3 键盘数据

键盘数据包括键盘扫描码和命令响应码。键盘扫描码是用户按下键盘按键时键盘发送给系统的数据不同的键其码值是不同的。可通过查阅有关资料〔‘〕或测试获得。命令响

应码则是键盘对系统命令的响应。其含义如下:

(1) FE H 请求重发一一对收到一个奇偶校验错或无效命令时请求系统重发命令;

(2) FA H 正常应答一一对任何一个有效的键盘命令均以该响应作答;

(3 ) OOH 超限应答一一当用户按键速度超出键盘内缓冲器存放的16 个扫描码时

出该应答;

(4 ) FD H 诊断故障应答一一键盘在自测试过程中若有故障则以FD H 应答;

(5) A A I硕诊断正常应答一一键盘在自测试过程中若无故障则以A A H 应答;

(6) E E H 回响命令应答一一键盘收到系统的回响命令(E E H ) 也发一个E E H 

;

(7 ) FO H 断开扫描码前缀字节一一断开扫描码占两个字节第一个字节总是刊H , 

二个字节和接通扫描码相同。

2、接口及软件设计

微机键盘与单片机的接口如图

所示。

 

图 4

在此对单片机无特殊要求可采用

A T M[E L 公司的AI9 C5 1 单片机其指令系统和IN JE L 公司的MCS -51 系列单片机完全兼容。单片机Pl.7 连数据线1)A T,P3.2 (IN ,I0 )连时钟C LK。微机键盘与单片机只有建立正常的通信关系才能控制键盘及处理键盘数据

。因此在软件设计上本文着重于介绍键盘数据的接收、键盘命令的发送、键盘的自检和复位这三部分。在软件设计时键盘命令只需使用一个,即初始化键(F FH )。对键盘数据的接收不作奇偶校验以简化编程。

2.1 键盘数据的接收

键盘数据的接收用IN TO 外部中断方法来实现在时钟线C LK 为低电平时产生一次中断读取数据线D A I,一位数据。键盘通过时钟线C L K 产生个时钟脉冲使单片机产生次中断才接收完一帧信息。中断次数的识别由单元E IC 来完成,E IC 的初值为1 1, 每中断一次减1。当E IC 表明一帧信息接收完同时禁止外部中断(E XO = O)、禁止键盘发数据(C LK = 0 )、置数据接收完成标志bR ()K = 1 并使E IC 的初值为1 1 

键盘数据存放单元在K B D 其初值为# o fh, 每中断一次数据线1)A T K B D 左移一位数据同时K B D 也左移出一位当检测到K左移出起始位“ ” 时, K B D 中的内容即为要接收的键盘数据。当主程序处理完键盘数据K BD 为了接收下一帧信息应置C LK= 1,EXO = 1 

bR O K = 0

2.2.2 键盘命令的发送

键盘命令的发送采用刊中断方法来实现每次中断都对时钟线C LK 求反以产生n个脉冲把发送缓冲区SB LS13H 中的信息经数据线1A T 送给键盘。

中断次数由单元T IC来控制, T IC 的初值为2, 每中断一次减1。当T IC 一帧位信息发送完D A T= 1CL K = 1、命令发送完成标志b R ()K = 1, T IC 的初值为2, 并禁止定时器工作(T R O= 0 ), 为发送键盘命令或接收键盘数据作好准备。

SB HSB L 组成的发送缓冲区用于存放要发送的一帧位信息。其中S 13H 为高字

,SB L 为低字节一帧信息在该缓冲区中的存放格式如图所示。

图 5

其中: d0 位为一帧信息的起始位;

,d7 d l 为键盘命令(田为最高位,d1 为最低位) ;D l 为奇偶校验位;砚为停止位;其余未定义。如单片机时钟频率为12 M llz , 定时器工作方式1, 要确保键盘对时钟周期为5 0 u s 的要求则时间常数取值为TL0 = # ocdh,THO = # offh



助工
2015-01-10 14:13:35     打赏
10楼

8、吴鉴鹰单片机项目详细解析系列(连载)之基于单片机的微机键盘的运用 (二)——相关的程序编写

 

吴鉴鹰在本例中使用时一种标准的通讯程序,各位烧友可以参考参考一下Atmel公司发布的单片机在键盘中的应用笔记,这个程序我也是参考该应用笔记
给各位烧友分享的。
   除了有关的字符库外,吴鉴鹰的这个程序主要为4个部分:①、初始化 ②、串口通讯 ③、键盘 ④、数据处理
   1.程序功能
   该程序的主要功能是处理外接的微机键盘和单片机的数据通讯,这里吴鉴鹰就分为4个部分进行介绍
   ①Main.C:主程序,主要处理单片机和键盘通讯的初始化
   ②Low_level_init:键盘的初始化和通信协议的初始化
   ③Serial.c:串行通讯程序,处理数据的传输和收发
   ④Kb.C:键盘的按键处理程序,控制按键的谁和发送
   2、主要器件很函数的说明
   ⑴.Low_level_init.c:   初始化键盘和单片机的通信方式
   ⑵.Main():             主程序,初始化参数并等待中断产生
   ⑶.init_uart():        初始化串口的寄存器
   ⑷.init_kb():          初始化键盘的收发
   ⑸.getchar():          读取字符函数
   ⑹.putchar():          发送字符函数
   ⑺.delay():            延时函数
   ⑻.init_uart(void):    初始化串口
   ⑼.clr(void):          定义清屏函数
   ⑽.init_kb(void):      初始化键盘
   ⑾.decode(unsigned sc):键盘按键码解码函数
   ⑿.put_kbbuff(uchar):  键盘的输入字符函数
   
/*初始化程序*/ 
/*********************************************************************************************************
** 函数名称:   _Low_level_init  
** 功能描述:   这个函数的主要功能是对单片机的端口和串行通讯的波特率、通信方式等作一系列的规定很处理  
                                                          
** 输 入: 
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.03.2
********************************************************************************************************/
//Low_level_init.c
#include<ina90.h>
#include<io8585.h>
int  _Low_level_init(void)
{
   UBRR = 12;
   UCR = 0X08;
   GIMSK = 0X40;
   _SEI();
   return 1;
} 
   
   
/*主函数*/  
#include<pgmspace.h>
#include<stdio.h>
#include<stdlib.h>
#include "io8515.h"
#include "serial.h"
#include "gpr.h"
#include "kb.h"
/*********************************************************************************************************
** 函数名称:   main  
** 功能描述:   串口的初始化、初始化键盘的收发  
                                                          
** 输 入: 
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.03.2
********************************************************************************************************/
void main()
{
   unsigned char key;
   init_usart();                    //串口的初始化程序
   init_kb();                       //初始化键盘的收发
   while(1)
   {
      key = getchar();
   putchar(key);
   delay(100);                   //延时子程序
   }
}

/*键盘处理子程序*/
#include<pgmspace.h>
#include "kb.h"
#include "serial.h"
#include "qpr.h"
#include "scancodes.h"
#define BUFF_SIZE 64
unsigned char dege,bitcount;        //0 :符号,1 :正号
unsigned char kb_buffer[BUFFER_SIZE];
unsigned char *inpt,*outpt;
unsigned char buffercnt;
/*********************************************************************************************************
** 函数名称:   init_kb  
** 功能描述:   初始化键盘  
                                                          
** 输 入: 
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.03.2
********************************************************************************************************/
void init_kb(void)
{
    inpt = kb_buffer;                 //初始化缓冲区        
outpt = kb_buffer;
buffcnt = 0;
MCUCR = 2;                       //INT0中断,下降沿触发
edge = 0;                        //0:下降沿,1 :上升沿
bitcount = 11;
}
/*********************************************************************************************************
** 函数名称:   INT0_interrupt  
** 功能描述:   按键接收中断函数  
                                                          
** 输 入: 
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.03.2
********************************************************************************************************/interrupt  [INT0_vect]  void INT0_interrupt(void)
{
   static unsigned char data;            //保持接收扫描码的状态
   if(!edge)                             //下降沿触发中断服务程序
   {
      if(bitcount < 11 && bitcount > 2)  //3~10位是数据
   {                                  //删除起始位和停止位
     data = (data >> 1);             
  if(PIND & 8)
  data = data | 0x80;             //如果为“1”则存储          
   }
   MCUCR = 3;                         //设置该寄存器是为了用上升沿触发中断
   edge = 1;
   }
   else
   {
     MCUCR = 2;
  edge = 0;
  if(--bitcount == 0)               //该判断是接收到所有的中断的时候
  {
    decode(data);
    bitcount = 11;
  }
   }
}
/*********************************************************************************************************
** 函数名称:   decode  
** 功能描述:   键盘按键码解码函数 
                                                          
** 输 入: 
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.03.2
********************************************************************************************************/
void decode(unsigned char sc)
{
   static unsigned char is_up = 0,shift = 0,mode = 0;
   unsigned char i;
   if(!is_up)                          //最后一位数据的接收
   {
      switch(sc)
   {
     case 0xf0: is_up = 1;break;    //确定完成了的按键
  case 0x12: shift = 1;break;    //左边的shift键
  case 0x59: shift = 1;break;    //右边的shift键
  case 0x05:                     //F1键
  if(mode == 0) 
  {
    mode = 1;                    //进入按键扫描模式
  }
  if(mode == 2)                  //离开按键扫描模式
  {
    mode = 3;
  }
  break;
  default:
  if(mode == 0 || mode == 3)     //ASCΙΙ模式
  {
    if(!shift)                   //如果没有shift键被按下
    {                            //查表
      for(i=0;unshifted[0] != sc && unshifted[0];i++);
   if(unshifted[0] == sc)
   {
      put_kbuffer(unshifted[1]);
   }
    }
    else
    {                           //如果shift键被按下
         for(i = 0;shifted[0] != sc && shifted[0];i ++);
      if(shifted[0] == sc)
      {
         put_kbbuffer(shifted[1]);
      }
    }
  }
  else
  {
    print_hexbyte(sc);          //扫描键盘吗模式
    put_kbbuffer(' ');          //显示模式
    put_kbbuffer(' ');
  }
  break;
   }
   }
   else
   {
      is_up = 0;                      //2个0xf0在一列中不允许的
   switch(sc)
   {
       case 0x12:shift = 0;break;  //左shift
    case 0x59:shift = 0;break;  //右shift
    case 0x05:                  //F1
    {
      if(mode == 1)
   {
     mode = 2;
   }
   if(mode == 3)
   {
     mode = 0;
   }
   break;
   case 0x06:                //F2
   clr();
   break;
    }
   }
   } 
}
/*********************************************************************************************************
** 函数名称:   put_kbbuff  
** 功能描述:   键盘输入字符的函数 
                                                          
** 输 入: 
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.03.2
********************************************************************************************************/
void put_kbbuff(unsigned char c)
{
     if(buffcnt < BUFF_SIZE)                  //若缓冲区为空
     {
       *inpt = C;                          //在缓冲区中输入一个字符            
    inpt++;                             //指针加1
    buffcnt ++;
    if(inpt >= kb_buffer + BUFF_SIZE)   //指针判断
    {
       inpt = kb_buffer;
    }
  }    
}
/*********************************************************************************************************
** 函数名称:   getchar  
** 功能描述:   读取键盘输入字符的函数 
                                                          
** 输 入: 
**         
**         
** 输 出: 
** 全局变量:
** 调用模块: 
**
** 作 者:    吴鉴鹰
** 日 期:    14.03.2
********************************************************************************************************/
int  getchar(void)
{
   int byte;
   while(buffcnt == 0);                     //等待数据
   byte = *outpt;                           //取数据
   outpt++;                                 //指针加1
   if(outpt >= kb_buffer + BUFFER_SIZE)     //指针比较
   outpt = kb_buffer;
   buffcnt--;                               //缓冲区减去1
   return byte;
}



 


共31条 1/4 1 2 3 4 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]