单片机基础4.docx
- 文档编号:9746542
- 上传时间:2023-02-06
- 格式:DOCX
- 页数:20
- 大小:23.08KB
单片机基础4.docx
《单片机基础4.docx》由会员分享,可在线阅读,更多相关《单片机基础4.docx(20页珍藏版)》请在冰豆网上搜索。
单片机基础4
如果将8个发光二极管的负极(阴极)内接在一起,作为数码管的一个引脚,这种数码管则被称为共阴数码管,共同的引脚则称为共阴极,8个正极则为段极。
否则,如果是将正极(阳极)内接在一起引出的,则称为共阳数码管,共同的引脚则称为共阳极,8个负极则为段极。
以单支共阴数码管为例,可将段极接到某端口Pn,共阴极接GND,则可编写出对应十六进制码的七段码表字节数据如右图:
16键码显示的程序
我们在P1端口接一支共阴数码管SLED,在P2、P3端口接16个按键,分别编号为KEY_0、KEY_1到KEY_F,操作时只能按一个键,按键后SLED显示对应键编号。
#include
#defineSLEDP1
#defineKEY_0P2^0
#defineKEY_1P2^1
#defineKEY_2P2^2
#defineKEY_3P2^3
#defineKEY_4P2^4
#defineKEY_5P2^5
#defineKEY_6P2^6
#defineKEY_7P2^7
#defineKEY_8P3^0
#defineKEY_9P3^1
#defineKEY_AP3^2
#defineKEY_BP3^3
#defineKEY_CP3^4
#defineKEY_DP3^5
#defineKEY_EP3^6
#defineKEY_FP3^7
CodeunsignedcharSeg7Code[16]=//用十六进数作为数组下标,可直接取得对应的七段编码字节
//0123456789AbCdEF
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
voidmain(void)
{
unsignedchari=0;//作为数组下标
P2=0xff;//P2作为输入,初始化输出高
P3=0xff;//P3作为输入,初始化输出高
While
(1)
{
if(KEY_0==0)i=0;if(KEY_1==0)i=1;
if(KEY_2==0)i=2;if(KEY_3==0)i=3;
if(KEY_4==0)i=4;if(KEY_5==0)i=5;
if(KEY_6==0)i=6;if(KEY_7==0)i=7;
if(KEY_8==0)i=8;if(KEY_9==0)i=9;
if(KEY_A==0)i=0xA;if(KEY_B==0)i=0xB;
if(KEY_C==0)i=0xC;if(KEY_D==0)i=0xD;
if(KEY_E==0)i=0xE;if(KEY_F==0)i=0xF;
SLED=Seg7Code[i];//开始时显示0,根据i取应七段编码
}
}
第二节:
双数码管可调秒表
解:
只要满足题目要求,方法越简单越好。
由于单片机I/O资源足够,所以双数码管可接成静态显示方式,两个共阴数码管分别接在P1(秒十位)和P2(秒个位)口,它们的共阴极都接地,安排两个按键接在P3.2(十位数调整)和P3.3(个位数调整)上,为了方便计时,选用12MHz的晶体。
为了达到精确计时,选用定时器方式2,每计数250重载一次,即250us,定义一整数变量计数重载次数,这样计数4000次即为一秒。
定义两个字节变量S10和S1分别计算秒十位和秒个位。
编得如下程序:
#include
CodeunsignedcharSeg7Code[16]=//用十六进数作为数组下标,可直接取得对应的七段编码字节
//0123456789AbCdEF
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
voidmain(void)
{
unsignedintus250=0;
unsignedchars10=0;
unsignedchars1=0;
unsignedcharkey10=0;//记忆按键状态,为1按下
unsignedcharkey1=0;//记忆按键状态,为1按下
//初始化定时器Timer0
TMOD=(TMOD&0xF0)|0x02;
TH1=-250;//对于8位二进数来说,-250=6,也就是加250次1时为256,即为0
TR1=1;
while
(1){//----------循环1
P1=Seg7Code[s10];//显示秒十位
P2=Seg7Code[s1];//显示秒个位
while
(1){//----------循环2
//计时处理
if(TF0==1){
TF0=0;
if(++us250>=4000){
us250=0;
if(++s1>=10){
s1=0;
if(++s10>=6)s10=0;
}
break;//结束“循环2”,修改显示
}
}
//按十位键处理
P3.2=1;//P3.2作为输入,先要输出高电平
if(key10==1){//等松键
if(P3.2==1)key10=0;
}
else{//未按键
if(P3.2==0){
key10=1;
if(++s10>=6)s10=0;
break;//结束“循环2”,修改显示
}
}
//按个位键处理
P3.3=1;//P3.3作为输入,先要输出高电平
if(key1==1)//等松键
{if(P3.3==1)key1=0;}
else{//未按键
if(P3.3==0){key1=1;
if(++s1>=10)s1=0;
break;//结束“循环2”,修改显示
}
}
}//循环2’end
}//循环1’end
}//main’end
解:
用P1端口的6个引脚控制交通灯,高电平灯亮,低电平灯灭。
#include
//sbit用来定义一个符号位地址,方便编程,提高可读性,和可移植性
sbitSNRed=P1^0;//南北方向红灯
sbitSNYellow=P1^1;//南北方向黄灯
sbitSNGreen=P1^2;//南北方向绿灯
sbitEWRed=P1^3;//东西方向红灯
sbitEWYellow=P1^4;//东西方向黄灯
sbitEWGreen=P1^5;//东西方向绿灯
/*用软件产生延时一个单位时间*/
voidDelay1Unit(void)
{
unsignedinti,j;
for(i=0;i<1000;i++)
for(j<0;j<1000;j++);//通过实测,调整j循环次数,产生1ms延时
//还可以通过生成汇编程序来计算指令周期数,结合晶体频率来调整j循环次数,接近1ms
}
/*延时n个单位时间*/
voidDelay(unsignedintn){for(;n!
=0;n--)Delay1Unit();}
voidmain(void)
{
while
(1)
{
SNRed=0;SNYellow=0;SNGreen=1;EWRed=1;EWYellow=0;EWGreen=0;Delay(60);
SNRed=0;SNYellow=1;SNGreen=0;EWRed=1;EWYellow=0;EWGreen=0;Delay(10);
SNRed=1;SNYellow=0;SNGreen=0;EWRed=0;EWYellow=0;EWGreen=1;Delay(60);
SNRed=1;SNYellow=0;SNGreen=0;EWRed=0;EWYellow=1;EWGreen=0;Delay(10);
}
}
显示“12345678”
P1端口接8联共阴数码管SLED8的段极:
P1.7接段h,…,P1.0接段a
P2端口接8联共阴数码管SLED8的段极:
P2.7接左边的共阴极,…,P2.0接右边的共阴极
方案说明:
晶振频率fosc=12MHz,数码管采用动态刷新方式显示,在1ms定时断服务程序中实现
#include
unsignedcharDisBuf[8];//全局显示缓冲区,DisBuf[0]对应右SLED,DisBuf[7]对应左SLED,
voidDisplayBrush(void)
{codeunsignedcharcathode[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//阴极控制码
CodeunsignedcharSeg7Code[16]=//用十六进数作为数组下标,可直接取得对应的七段编码字节
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
staticunsignedchari=0;//(0≤i≤7)循环刷新显示,由于是静态变量,此赋值只做一次
P2=0xff;//显示消隐,以免下一段码值显示在前一支SLED
P1=Seg7Code[DisBuf[i]];//从显示缓冲区取出原始数据,查表变为七段码后送出显示
P2=cathode[i];//将对应阴极置低,显示
if(++i>=8)i=0;//指向下一个数码管和相应数据
}
voidTimer0IntRoute(void)interrupt1
{
TL0=-1000;//由于TL0只有8bits,所以将(-1000)低8位赋给TL0
TH0=(-1000)>>8;//取(-1000)的高8位赋给TH0,重新定时1ms
DisplayBrush();
}
voidTimer0Init(void)
{TMOD=(TMOD&0xf0)|0x01;//初始化,定时器T0,工作方式1
TL0=-1000;//定时1ms
TH0=(-1000)>>8;
TR0=1;//允许T0开始计数
ET0=1;//允许T0计数溢出时产生中断请求
}
voidDisplay(unsignedcharindex,unsignedchardataValue){DisBuf[index]=dataValue;}
voidmain(void)
{
unsignedchari;
for(i=0;i<8;i++){Display(i,8-i);区qhkode[DisBuf[i]];//;f7,0xfd,0xfb,0xfe};
}//DisBuf[0]为右,DisBuf[7]为左
Timer0Init();
EA=1;//允许CPU响应中断请求
While
(1);
}
指提供一些函数给任务调用,获取按键信息,或读取按键值。
定义一个头文档
#ifndef_KEY_H_//防止重复引用该文档,如果没有定义过符号_KEY_H_,则编译下面语句
#define_KEY_H_//只要引用过一次,即#include
unsignedcharkeyHit(void);//如果按键,则返回非0,否则返回0
unsignedcharkeyGet(void);//读取按键值,如果没有按键则等待到按键为止
voidkeyPut(unsignedcharucKeyVal);//保存按键值ucKeyVal到按键缓冲队列末
voidkeyBack(unsignedcharucKeyVal);//退回键值ucKeyVal到按键缓冲队列首
#endif
定义函数体文档KEY.C,如下:
#include“key.h”
#defineKeyBufSize16//定义按键缓冲队列字节数
unsignedcharKeyBuf[KeyBufSize];//定义一个无符号字符数组作为按键缓冲队列。
该队列为先进
//先出,循环存取,下标从0到KeyBufSize-1
unsignedcharKeyBufWp=0;//作为数组下标变量,记录存入位置
unsignedcharKeyBufRp=0;//作为数组下标变量,记录读出位置
//如果存入位置与读出位置相同,则表明队列中无按键数据
unsignedcharkeyHit(void)
{if(KeyBufWp==KeyBufRp)return(0);elsereturn
(1);}
unsignedcharkeyGet(void)
{unsignedcharretVal;//暂存读出键值
while(keyHit()==0);//等待按键,因为函数keyHit()的返回值为0表示无按键
retVal=KeyBuf[KeyBufRp];//从数组中读出键值
if(++KeyBufRp>=KeyBufSize)KeyBufRp=0;//读位置加1,超出队列则循环回初始位置
return(retVal);
}
voidkeyPut(unsignedcharucKeyVal)
{KeyBuf[KeyBufWp]=ucKeyVal;//键值存入数组
if(++KeyBufWp>=KeyBufSize)KeyBufWp=0;//存入位置加1,超出队列则循环回初始位置
}
/*****************************************************************************************
由于某种原因,读出的按键,没有用,但其它任务要用该按键,但传送又不方便。
此时可以退回按键队列。
就如取错了信件,有必要退回一样
******************************************************************************************/
voidkeyBack(unsignedcharucKeyVal)
{
/*
如果KeyBufRp=0;减1后则为FFH,大于KeyBufSize,即从数组头退回到数组尾。
或者由于干扰使得KeyBufRp超出队列位置,也要调整回到正常位置,
*/
if(--KeyBufRp>=KeyBufSize)KeyBufRp=KeyBufSize-1;
KeyBuf[KeyBufRp]=ucKeyVal;//回存键值
}
下面渐进讲解键盘物理层的驱动。
电路共同点:
P2端口接一共阴数码管,共阴极接GND,P2.0接a段、P2.1接b段、…、P2.7接h段。
软件共同点:
codeunsignedcharSeg7Code[10]是七段数码管共阴编码表。
CodeunsignedcharSeg7Code[16]=
//0123456789AbCdEF
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
例一:
P1.0接一按键到GND,键编号为‘6’,显示按键。
#include
#include“KEY.H”
voidmain(void)
{P1_0=1;//作为输入引脚,必须先输出高电平
while
(1)//永远为真,即死循环
{if(P1_0==0)//如果按键,则为低电平
{keyPut(6);//保存按键编号值为按键队列
while(P1_0==0);//如果一直按着键,则不停地执行该循环,实际是等待松键
}
if(keyHit()!
=0)//如果队列中有按键
P2=Seg7Code[keyGet()];//从队列中取出按键值,并显示在数码管上
}
}
例二:
在例一中考虑按键20ms抖动问题。
#include
#include“KEY.H”
voidmain(void)
{P1_0=1;//作为输入引脚,必须先输出高电平
while
(1)//永远为真,即死循环
{if(P1_0==0)//如果按键,则为低电平
{delay20ms();//延时20ms,跳过接下抖动
keyPut(6);//保存按键编号值为按键队列
while(P1_0==0);//如果一直按着键,则不停地执行该循环,实际是等待松键
delay20ms();//延时20ms,跳过松开抖动
}
if(keyHit()!
=0)//如果队列中有按键
P2=Seg7Code[keyGet()];//从队列中取出按键值,并显示在数码管上
}
}
例三:
在例二中考虑干扰问题。
即小于20ms的负脉冲干扰。
#include
#include“KEY.H”
voidmain(void)
{P1_0=1;//作为输入引脚,必须先输出高电平
while
(1)//永远为真,即死循环
{if(P1_0==0)//如果按键,则为低电平
{delay20ms();//延时20ms,跳过接下抖动
if(P1_0==1)continue;//假按键
keyPut(6);//保存按键编号值为按键队列
while(P1_0==0);//如果一直按着键,则不停地执行该循环,实际是等待松键
delay20ms();//延时20ms,跳过松开抖动
}
if(keyHit()!
=0)//如果队列中有按键
P2=Seg7Code[keyGet()];//从队列中取出按键值,并显示在数码管上
}
}
例四:
状态图编程法。
通过20ms周期中断,扫描按键。
/****************************************************************************************
采用晶体为12KHz时,指令周期为1ms(即主频为1KHz),这样T0工作在定时器方式2,8位自动重载。
计数值为20,即可产生20ms的周期性中断,在中断服务程序中实现按键扫描
*****************************************************************************************/
#include
#include“KEY.H”
voidmain(void)
{
TMOD=(TMOD&0xf0)|0x02;//不改变T1的工作方式,T0为定时器方式2
TH0=-20;//计数周期为20个主频脉,即20ms
TL0=TH0;//先软加载一次计数值
TR0=1;//允许T0开始计数
ET0=1;//允许T0计数溢出时产生中断请求
EA=1;//允许CPU响应中断请求
while
(1)//永远为真,即死循环
{
if(keyHit()!
=0)//如果队列中有按键
P2=Seg7Code[keyGet()];//从队列中取出按键值,并显示在数码管上
}
}
voidtimer0int(void)interrupt1//20ms;T0的中断号为1
{staticunsignedcharsts=0;
P1_0=1;//作为输入引脚,必须先输出高电平
switch(sts)
{
case0:
if(P1_0==0)sts=1;break;//按键则转入状态1
case1:
if(P1_0==1)sts=0;//假按错,或干扰,回状态0
else{sts=2;keyPut(6);}//确实按键,键值入队列,并转状态2
break;
case2:
if(P1_0==1)sts=3;break;//如果松键,则转状态3
case3:
if(P1_0==0)sts=2;//假松键,回状态2
elsests=0;//真松键,回状态0,等待下一次按键过程
}
}
例五:
状态图编程法。
/****************************************************************************************
如果采用晶体为12MHz时,指令周期为1us(即主频为1MHz),要产生20ms左右的计时,则计数值达到20000,T0工作必须为定时器方式1,16位非自动重载,即可产生20ms的周期性中断,在中断服务程序中实现按键扫描
*****************************************************************************************/
#include
#include“KEY.H”
voidmain(voi
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 单片机 基础