⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ex9.c

📁 C51的4×3键盘、LED数码显示、串行通讯
💻 C
字号:
/*************************************************************
		程序功能描述
	利用实验开发系统上的3×4键盘矩阵仿造手机键盘的布局,
	按下0~9的数字键时,数值依次在LED上显示,定义‘*’键
	为退格键,‘#’键为发送键,可将按键输入的内容,利用
	uPSD3251的UART0口,通过开发系统的RS232接口发送到PC
	机上,即可在串口调试软件上看到发送的数据。设定每次
	发送的消息最长为8个字节。
	CPU晶振频率为11.0592MHz,串口波特率为9600。
**************************************************************/
#include "upsd.h"
#include <stdio.h>		//引入标准I/O函数的声明
#define	uchar unsigned char

bit keydown = 0;		//有键按下的标志位
uchar load_ptr,scancode,keycount;	

xdata uchar CONTROL_B _at_ 0x803;
xdata uchar DATAOUT_B _at_ 0x805;
xdata uchar DIRECTION_B	_at_ 0x807;
uchar position;			// LED的位码存储单元
uchar a[8];				// 8字节长显示缓冲区
uchar *disp_ptr;		// 显示缓冲区的指针
uchar code led_code[11] = {0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09,0xef};
//数字码表0-9,LED无显示下划线‘_’时对应码值为0xef

#define TIMER0_COUNT 0xf8CD			// TH0=0xf8,TL0=0xcd,在11.0592MHz的晶振频率下,可实现2ms的计数
bit timer0int;				// timer0int是定时器0的中断标志位

/**********初始化定时器0**********/
void timer0_init(void)		
{
	TMOD &= 0xf0;
	TMOD |= 0x01;			// 定时器0,工作方式为方式1
	TL0 = (TIMER0_COUNT & 0x00ff);	// 设置低8位计数值
	TH0 = (TIMER0_COUNT >> 8);		// 设置高8位计数值
	PT0 = 0;				// 低优先级
	ET0 = 1;				// 使能定时器0中断源	
	EA = 1;					// 允许所有中断源
	TR0 = 1;				// 启动定时器0
	timer0int = 0;			// 初始化定时器0的中断标志timer0int为0
}
/*定时器0的中断服务程序,每次中断置中断标志位*/
void timer0isr(void) interrupt 1						
{	
	TL0 = TL0 + (TIMER0_COUNT & 0x00FF);	// 重载低8位计数值
	TH0 = TH0 + (TIMER0_COUNT >> 8);		// 重载高8位计数值
 	timer0int = 1;			// 置中断标志
}
/********LED显示的初始化********/
void led_init(void)			
{
	CONTROL_B = 0;			// 初始化PB口为MCU模式
	DATAOUT_B = 0;			// 将PB口的输出数据寄存器清零
	DIRECTION_B = 0xff;		// PB口数据传输方向为输出
	position = 0x80;		// 初始化位码为0x80
	disp_ptr = &a;			// 初始化显示缓冲区指针disp_ptr指向a[0]
}
/*1位LED显示,并更新位码和显示缓冲指针*/
void display(void)			
{	
	P4 = 0xff;				// 熄影
	DATAOUT_B = position;			// 输出位码
	position = position>>1;			// 更新位码
	if(position == 0) position = 0x80;
	P4 = led_code[*disp_ptr++];		// 输出段码
	if(position == 0x80) disp_ptr = &a;		// 更新显示缓冲指针
}
/**********初始化UART0**********/
void uart0_init()
{
    SCON  = 0x50;				//串口方式1,接收允许
	TMOD &= 0x0f;
    TMOD |= 0x20;               //定时器1,方式2
    TH1   = 0xfd;               //9600波特率11.0592MHz
	TL1   = 0xfd;
    TR1   = 1;             		//启动定时器1
    TI    = 1;             		//启动发送
}
/*********初始化显示缓冲区*********/
void buff_init()
{
	a[0] = 10; a[1] = 10; a[2] = 10; a[3] = 10;	//将显示缓冲区的值均设为10
	a[4] = 10; a[5] = 10; a[6] = 10; a[7] = 10;	//使LED显示下划线‘_’
	load_ptr = 0;				//初始化显示缓冲区的装载指针为0
}
/****键盘扫描,返回扫描码,无键按下返回0****/
uchar kscan(void)			
{	
	uchar hcode,lcode;
 	P1 = 0xf0;			//发全0行扫描码,列线输入
 	if((P1&0xf0) != 0xf0) 		//若有键按下
	{	
		if((++keycount >= 10) && !keydown)	//延时20ms去抖动
		{	
			keydown = 1;				//置有键按下的标志位			
			lcode = P1&0xf0;			//得列码值
			P1 = 0x0f;
			hcode = P1&0x0f;			//得行码值			
			return(~(hcode+lcode));		//返回键值
		}
	}	
	else				//无键按下
	{
		keycount=0; 		//按键的延时计数器清零
		keydown=0;		//按键标志清零
	}
		return(0);		//无键按下或旧键未放开,返回值为0	 
}
/**********键处理函数*********/
void keydeal(uchar val)			
{	
	uchar i;
	if(load_ptr<=7)				//显示缓冲区未写满
		switch(val)			//根据扫描码来决定键处理的动作			
	  	{	
			case 0x11:	a[load_ptr++] = 1; break;		//‘1’键按下,装载1至显示缓冲区
			case 0x21:	a[load_ptr++] = 2; break;
			case 0x41:	a[load_ptr++] = 3; break;
			case 0x12:	a[load_ptr++] = 4; break;
			case 0x22:	a[load_ptr++] = 5; break;	
			case 0x42:	a[load_ptr++] = 6; break;
			case 0x14:	a[load_ptr++] = 7; break;
			case 0x24:	a[load_ptr++] = 8; break;
			case 0x44:	a[load_ptr++] = 9; break;
			case 0x28:	a[load_ptr++] = 0; break;
			case 0x18:	if(load_ptr != 0) a[--load_ptr] = 10; 	//若显示缓冲区不为空,则前一缓冲单元赋10	
					break;
			case 0x48:	if(load_ptr != 0) 
					{
						for(i=0;i<8;i++)
							if(a[i]!=10)putchar(a[i]+0x30);	//将键盘输入内容的ASCII码通过URAT0发送出去
						buff_init();		//显示缓冲区重新初始化
					}break;
			default	 :	break;
	  	}
	else					//显示缓冲区已写满
	{
		if(val==0x18) a[--load_ptr] = 10;		//若为退格键,将a[7]单元赋10
		if(val==0x48) 			//若为发送键
		{
			for(i=0;i<8;i++) putchar(a[i]+0x30);		//发送键盘输入内容的ASCII码
			buff_init();		
		}
	}		
}  	 
						
main()
{	
	WDKEY=0x55;
	timer0_init();
	uart0_init();
	led_init();	
 	buff_init();
 	for(;;)
    	{	
		if(timer0int)	
        	{	
			timer0int = 0;		//2ms到,清中断标志		   		
	   		display();			//LED显示
			scancode = kscan();		//扫描键盘
			if(scancode) keydeal(scancode);	//扫描码不为0,即有键按下,则对按键进行处理								
		}  
 	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -