51/AVR单片机技术驿站!  <在线翻译>     便利工具    特色网址   无弹窗、无插件的绿色站点...  英才招聘   学历查询  喜欢>>收藏我站 

当前位置:首页 > ◆本站实例 > 详细内容
输入输出共用端口的范例(LCD1602显示计数)
作者:月夜听风  发布时间:2010/5/15  阅读次数:3590  字体大小: 【】 【】【

  

       单片机的I/O数量有限,很多时候在实际应用中你要考虑共用端口(比如小尺寸控制器,不方便用管脚多的单片机,另外体积大)。
  
       大家看了下面的电路图后就会发现:LCD的数据信号线占用了P1,而P1同时又是三个按键的输入端口。这样可能有的朋友会说,用LCD的同时也想使用P1当其他控制信号输入端,岂不是冲突,不!可以的。因为您的思想停留在一个概念:I/O要么只能当输入、要么当只能输出。单片机不是那么没用的,要不然不会很多人好奇地去学,关键是你怎么去控制,在此我提示一下:一个端口在当输入的时候也能实现输出,关键的因素是要找个时间差来错过冲突


电路接线方法示意图,共用端口也无妨,功能照样去做)

       首先,LCD和LED数码管不同,只要您保持了电源,即使断开了信号它也能保持当前显示状态。好的,第一个疑问解除了。在您送了显示的更新数据后,立刻把P1全部设为1,为P1做其他输入信号创造条件,然后紧接着检测输入状态(比如按键),检测到后执行你想做的其他事情,如果是显示,就给出更新显示命令,完成一个事情后继续把P1设为1,接下来再做检测、就是以此类推的意思。单片机的执行速度非常快,看似有些步骤,其实反应就是瞬间的事。

  

(按键计数1602显示截图)

//====================================================================
// 程序名称:LCD1602显示计数( 0~9999计数范围 ) 程序
//                     本程序不包含EEPROM测试,XY-30B另有EEPROM应用范例
// 实验对象:XY-30B单片机工控板(点击查看产品), 核心:STC12C5A16S2
// 功       能:
// 每按一次开关KEY1(接X0)键,LCD1602便更新显示加1后的数据;
// 每按一次开关KEY2(接X1)键是减1操作,按KEY3(接X2)键是清零操作。
// 编       写:kenny Wan       http://www.mcusy.cn
//===================================================================*/
#include <stc_new_8051.H>   //新一代1T型51单片机头文件
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
//-------------------------------------------------------------------
#define DataPort P1   // LCD接口
sbit RS = P0^5;   // LCD读写控制
sbit RW = P0^6;
sbit EN = P0^7;
sbit KEY1 = P1^0;   // 加1按键(也可接传感器数字计数信号)
sbit KEY2 = P1^1;   // 减1按键
sbit KEY3 = P1^2;   // 清0按键
uchar code tab0[] = {" MODEL : XY-30B "};   // 第一行
uchar code tab1[] = {" Q =00000             "};   // 第二行
uint count;  
//====================== 延时程序 ===========================//
void delay(uint z)
{
   uint x,y;
   for(x=z;x>0;x--)
   for(y=925;y>0;y--); //12M晶体/约1MS为初
}
//=================函数名:LCD检测信号======================//
void WaitEnable(void)
{        
     DataPort = 0xff;  
     RS = 0; RW = 1; _nop_();
     EN=1; _nop_(); _nop_();
     while(DataPort&0x80);
     EN=0;      
}        
//------------------- 函数名:写命令到LCD -------------------//
void WriteCommand(uchar Order,uchar Attribc)
{        
     if(Attribc)WaitEnable();
     RS = 0; RW = 0; _nop_();
     DataPort=Order; _nop_();
     EN = 1;
     _nop_(); _nop_();
     EN = 0;
}        
//------------------- 函数名: LCD写数据 --------------------//
void WriteData(uchar dataW)
{        
     WaitEnable();  
     RS = 1; RW = 0; _nop_();
     DataPort=dataW; _nop_();
     EN = 1;
     _nop_(); _nop_();
     EN = 0;
}    
//------------ 函数名:显示指定坐标的一个字符 -------------//
void DisplayOne(uchar X,uchar Y,uchar DData)
{          
     Y&=1; X&=15;          
     if(Y)X|= 0x40; X|= 0x80;    
     WriteCommand(X,0);  
     WriteData(DData);  
}          
//------------- 函数名:显示指定坐标的一串字符 --------------//
void DisplayList(uchar X,uchar Y,uchar code *DData)
{
     uchar ListLength=0;
     Y&= 0x1; X&= 0xF;                              
     while(X<=15)                        
       {                                            
           DisplayOne(X,Y,DData[ListLength]);
           ListLength++; X++;                                
       }                                        
}
//----------------- 函数名: LCD初始化 --------------------//
void InitLcd()      
{      
     char n;
     WriteCommand(0x38,1);
     WriteCommand(0x08,1);
     WriteCommand(0x01,1);
     WriteCommand(0x06,1);
     WriteCommand(0x0c,1);
     for(n=15;n>=0;n--)   //显示第一行
         {DisplayList(n,0,tab0); delay(100);}
     for(n=15;n>=0;n--)   //显示第二行
         {DisplayList(n,1,tab1); delay(100);}
}    
//============= 函数名:LCD显示函数 ==============//
void display(uint count)
{
     uchar w,q,b,s,g; //分离的变量      
     w=count/10000+0x30; //万位数
     q=count/1000%10+0x30; //千位数
     b=count/100%10+0x30; //百位数
     s=count/10%10+0x30; //十位数
     g=count%10+0x30; //个位数
     //以下为显示位置
     DisplayOne(4,1,w);_nop_();
     DisplayOne(5,1,q);_nop_();
     DisplayOne(6,1,b);_nop_();
     DisplayOne(7,1,s);_nop_();
     DisplayOne(8,1,g);_nop_();
}

//==================== 函数名:主函数 ========================//
void main(void)    
{
   P0M1=0x00;
   P0M0=0xff; //P0设成强推挽输出(AT89S5x和STC89C5x系列等均无此功能)
   P0=0x00; //P0初始化为低电平
   InitLcd();   //LCD初始化
   delay(100);
   display(count);
     while(1)
         {
             P1=0XFF;  //先把P1全部设全1
             if(KEY1==0) //加1键(可接入传感器计数信号)
                   {
                       delay(50); while(KEY1==0); //防抖延时(视情况可修改);是否放开了按
                       count++; display(count); //count的值加1并刷新显示
                       if(count==10000){count=0;} //若加满了10000个便清零
                   }
             P1=0XFF;
       if(KEY2==0) //减1键
                   {
                       delay(50); while(KEY2==0);
                       count--; display(count); //count的值减1并刷新显示
                       if(count==0){count=10000;} //若减到了0个,便赋值10000
                   }
             P1=0XFF;
       if(KEY3==0) //清零键
                   {
                       delay(50); while(KEY3==0);
                       count=0;display(count);  //count的值减1并刷新显示
                   }
             P1=0XFF;
         }
}

  

上一篇:键盘+可调时钟+计算器+I2C闹钟(ADC0809扩展) 下一篇:没有了!

网站导航 管理登陆 ┊ 免责声明 问题反馈  友链说明
本站部分内容来自网络共享资源,如有冒犯您的权利请来信告之删除或纠正!
不得对本站进行复制、盗链或镜像,转载内容须获得同意或授权;欢迎友情链接、站务合作!

    我要报警 Alexa
 mcusy_cn#126.com (请把#改成@) 交流:522422171
本站学习交流群:138..158(高级群1-)、77930286(高级群2)、61804809(群3)
Copyright© MCUSY All Rights Reserved
本站网警备案号: WZ36040002485
  ICP备案证书号:粤ICP备09034963号