📄 ex9.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 + -