乐高
发表于 2025-1-19 10:12:52
神农鼎 发表于 2025-1-19 09:16
《8051U深度入门到32位51大型实战视频》,【免费 + 包邮 送】实验箱@Ai8051U,100万套 - TinyML,Ai8051U...
这一段只详细讲了功能2:在数码管上显示4字节长整型数;功能1没有展开讲,只是一笔带过。
乐高
发表于 2025-1-20 14:59:08
第11集矩阵按键课后小练
简易洗衣机面板
1.按下开机键后,数码管显示1,表示默认为清洗模式1;
2.用矩阵按键模拟洗衣机的操作面板,前五个按键模拟1-5的清洗模式按键,选择几的时候数码管显示数字几,表示以当前为第几个功能;
3.按下启动后,按照选择的模式对应的时间开始倒计时,倒计时结束后,数码管熄灭,表示清洗完成(清洗时间自己随意设置)。
因为手头没有合适的矩阵键盘所以今天现焊了一块4 x 4的矩阵键盘。
1-5键设置了模式参数,16键设置为启动键。6-15键没设置,为空键。
矩阵键盘接口为P2口。数码管显示采用HC595驱动的8位数码管,但只驱动了末后两位。程序在冲哥的第11集DEMO程序的基础上稍作了一些增减。
下面为矩阵键盘扫描程序
void KEY_Task(void) //4*4矩阵键盘扫描
{//#define key P2 //矩阵键盘的数据口为P2
u8 key_temp;
u8 key1,key2;
key=0xf0;
key1=key;
if(key1 != 0xf0 )
{
key1=key&0xf0; //确定哪一行的按键按下
key=0x0f;
key2=key;
if(key2 != 0x0f )
key2=key&0x0f; //确定哪一列的按键按下
key_temp=key1|key2; //确定按键位置
}
// else
// key_temp = no_key ;
switch(key_temp) //当确定按键按下后,列举所有的按键情况
{
case 0xee: key_value=0;break;
case 0xde: key_value=1;break;
case 0xbe: key_value=2;break;
case 0x7e: key_value=3;break;
case 0xed: key_value=4;break;
case 0xdd: key_value=5;break;
case 0xbd: key_value=6;break;
case 0x7d: key_value=7;break;
case 0xeb: key_value=8;break;
case 0xdb: key_value=9;break;
case 0xbb: key_value=10;break;
case 0x7b: key_value=11;break;
case 0xe7: key_value=12;break;
case 0xd7: key_value=13;break;
case 0xb7: key_value=14;break;
case 0x77: key_value=15;break;
// case 0xff: key_value=16;break;
}
switch(key_value)
{
case 0: fen = 10;break; //赋予1-5各按键所表示模式运行时间
case 1: fen = 11;break;
case 2: fen = 12;break;
case 3: fen = 13;break;
case 4: fen = 14;break;
case 15: start = 1;break; //第16键设置为启动工作键
}
}数码管显示程序:
u8 SEG_NUM[]= //数码管段码数组
{
0x3F, /*'0', 0*/
0x06, /*'1', 1*/
0x5B, /*'2', 2*/
0x4F, /*'3', 3*/
0x66, /*'4', 4*/
0x6D, /*'5', 5*/
0x7D, /*'6', 6*/
0x07, /*'7', 7*/
0x7F, /*'8', 8*/
0x6F, /*'9', 9*/
0x77, /*'A', 10*/
0x7C, /*'B', 11*/
0x39, /*'C', 12*/
0x5E, /*'D', 13*/
0x79, /*'E', 14*/
0x71, /*'F', 15*/
0x40, /*'-', 16*/
0x00, /*' ', 17*/
0x80, /*'.', 18*/
};
void Seg_Task(void)
{
if(key_value != 15) //按任意一个模式选择键,回到等待启动状态
start = 0;
if(start) //启动工作后数码管显示倒计时时间,否则显示模式编号
num = fen;
else
num = key_value+1; //+1 为默认模式号为1
if( Seg_no ==0 )
{
if(num%10==0&&num/10==0) //如果十位和个位都为0,则消隐
Display_Seg( SEG_NUM , ~T_NUM);
else
Display_Seg( SEG_NUM , ~T_NUM); //显示个位数字
}
else if( Seg_no ==1 )
{
if(num/10==0) //如果十位为0,则消隐
Display_Seg( SEG_NUM , ~T_NUM);
else
Display_Seg( SEG_NUM , ~T_NUM);
}
else
{ }
Seg_no ++;
if( Seg_no>1 )
Seg_no=0;
}ISP软件端虚拟数码管显示程序:
void SEG_PC( void ) //只显示末两位
{
u8 cod;
cod = SEG_NUM;
cod = SEG_NUM;
cod =SEG_NUM;
cod = SEG_NUM;
cod = SEG_NUM;
cod = SEG_NUM;
if(num/10==0) //如果十位为0,则消隐
cod = SEG_NUM;
else
cod = SEG_NUM;
if(num/10==0 && num%10==0) //如果十位和个位都为0,则消隐
cod = SEG_NUM;
else
cod = SEG_NUM;
SEG7_ShowCode(cod);
}放上完整演示视频
530
乐高
发表于 2025-1-21 09:58:01
第十一集矩阵键盘 任意端口组合矩阵键盘数据口
前面的矩阵键盘接口程序用了一个完整的8位P2口,这样编写程序比较简单明了。如果矩阵键盘接的不在一个口上,就不能用前面的程序了,需要加以处理才能使用。
如果矩阵键盘8个接口如下
sbit COL1 = P2^0; //矩阵键盘的数据口端口定义
sbit COL2 = P2^1;
sbit COL3 = P2^2;
sbit COL4 = P2^3;
sbit ROW1 = P5^7;
sbit ROW2 = P5^6;
sbit ROW3 = P3^7;
sbit ROW4 = P3^6;需要使用如下的代码进行处理
//矩阵端口数据处理,逐位放入对应的IO口
void Matrixkey_W(u8 m) //向8个管脚写入数据
{
COL1 = m & (0x01<<0);
COL2 = m & (0x01<<1);
COL3 = m & (0x01<<2);
COL4 = m & (0x01<<3);
ROW1 = m & (0x01<<4);
ROW2 = m & (0x01<<5);
ROW3 = m & (0x01<<6);
ROW4 = m & (0x01<<7);
}
u8 Matrixkey_R() //从8个管脚读出数据
{
u8 n;
n&= (u8)COL1;
// if(COL1) //这个地方有个疑问,如用了这两行代码,程序跑起来就不正常,
// n |= 0x01; //改用上一条代码,程序就正常,真是奇了怪了!
if(COL2)
n |= 0x02;
if(COL3)
n|= 0x04;
if(COL4)
n |= 0x08;
if(ROW1)
n |= 0x10;
if(ROW2)
n |= 0x20;
if(ROW3)
n |= 0x40;
if(ROW4)
n |= 0x80;
return n;
}void KEY_Task(void) //4*4矩阵键盘扫描
{
u8 key_temp;
u8 key1,key2;
Matrixkey_W(0xf0);
key1 = Matrixkey_R();
if(key1 != 0xf0 )
{
key1 = Matrixkey_R()&0xf0; //确定哪一行的按键按下
Matrixkey_W(0x0f);
key2 = Matrixkey_R();
if(key2 != 0x0f)
key2 = Matrixkey_R()&0x0f; //确定哪一列的按键按下
key_temp=key1|key2; //确定按键位置
}
switch(key_temp) //当确定按键按下后,列举所有的按键情况
{
case 0xee: key_value=0;break;
case 0xde: key_value=1;break;
case 0xbe: key_value=2;break;
case 0x7e: key_value=3;break;
case 0xed: key_value=4;break;
case 0xdd: key_value=5;break;
case 0xbd: key_value=6;break;
case 0x7d: key_value=7;break;
case 0xeb: key_value=8;break;
case 0xdb: key_value=9;break;
case 0xbb: key_value=10;break;
case 0x7b: key_value=11;break;
case 0xe7: key_value=12;break;
case 0xd7: key_value=13;break;
case 0xb7: key_value=14;break;
case 0x77: key_value=15;break;
// case 0xff: key_value=16;break;
}
switch(key_value)
{
case 0: fen = 10;break; //赋予1-5各按键所表示模式运行时间
case 1: fen = 11;break;
case 2: fen = 12;break;
case 3: fen = 13;break;
case 4: fen = 14;break;
case 15: start = 1;break; //第16键设置为启动工作键
}
}
其他代码不变,还是沿用前面附件里的程序。
芯征程
发表于 2025-1-21 11:40:59
感谢您的支持与任何,今天给您免费包邮送AI8051U实验箱,期待您更多的测评
电子DIY小家
发表于 2025-1-21 12:04:03
乐高 发表于 2025-1-19 08:44
有一个问题想请教一下:
STC_ISP 调试仿真接口下面的调试接口协议中,7段数码管接口的功能1:
和printf用法一样的,只是要考虑数码管不能显示一些特殊的字符和汉字等等,只要能显示的字符和数字就能直接当printf这么用~!
乐高
发表于 2025-1-21 12:19:20
电子DIY小家 发表于 2025-1-21 12:04
和printf用法一样的,只是要考虑数码管不能显示一些特殊的字符和汉字等等,只要能显示的字符和数字就能 ...
谢谢版主的回复,现在明白了!
乐高
发表于 2025-1-21 14:08:31
第13楼 矩阵键盘 任意端口组合矩阵键盘数据口
程序的疑问已经解决。只要在Matrixkey_R()函数内定义n的时候预赋值为0就可以了。不是说好的定义默认值为0的吗?
u8 Matrixkey_R() //从8个管脚读出数据
{
u8 n =0;
// n&= (u8)COL1;这条语句就不用了
if(COL1)
n |= 0x01;
if(COL2)
n |= 0x02;
if(COL3)
n|= 0x04;
if(COL4)
n |= 0x08;
if(ROW1)
n |= 0x10;
if(ROW2)
n |= 0x20;
if(ROW3)
n |= 0x40;
if(ROW4)
n |= 0x80;
return n;
}
乐高
发表于 2025-1-22 14:04:20
第12集 复位系统 课后小练
这一课的课后小练是在第10课的基础上加了看门狗复位,开机LOGO,以及按键复位。
密码从“12345678”改为“12345670”,便于实验箱2x4矩阵键盘输入。
由于马上要回老家过年了,时间太仓促,程序没有整理。没有做完硬件矩阵按键数码管和虚拟键盘数码管共同操作的程序。
以后有时间再慢慢修改,完善。
534
乐高
发表于 2025-1-28 20:30:55
第十三集 外部中断
#include "ai8051u.h"
#include "stc32_stc8_usb.h"
#include "intrins.h"
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void Delay20ms(void);
void main()
{
P_SW2 |= 0x80; //外设端口切换寄存器,P_SW2第7位EAXFR置一使能访问XFR
CKCON = 0x00;
WTST = 0x00;
P0M1 = 0x00; P0M0 = 0x00;
P1M1 = 0x00; P1M0 = 0x00;
P2M1 = 0x00; P2M0 = 0x00;
P3M1 = 0x00; P3M0 = 0x00;
P4M1 = 0x00; P4M0 = 0x00;
P5M1 = 0x00; P5M0 = 0x00;
P6M1 = 0x00; P6M0 = 0x00;
P7M1 = 0x00; P7M0 = 0x00;
usb_init(); //USB CDC 接口配置
IE2 |= 0x80; //使能USB中断
IT1 = 1; //使能INT1下降沿中断
EX1 = 1; //使能INT1中断
EA = 1;
P40 = 0;
P06=0;
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
while (1)
{
if (bUsbOutReady)
{
USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
usb_OUT_done();
}
if(P01==0)
{
Delay20ms();
if(P01==0)
P00 = 0;
while(P01==0);
}
}
}
void INT1_Isr() interrupt 2
{
P00 = 1;
}
void Delay20ms(void) //@24.000MHz
{
unsigned long edata i;
_nop_();
_nop_();
i = 119998UL;
while (i) i--;
}581
乐高
发表于 2025-1-28 20:50:38
第十四集IO中断
void common_isr() interrupt 37
{
u8 intf;
intf = P0INTF;
if(intf)
{
P0INTF = 0x00;
if(intf & 0x02)
{key_num = 1;P0INTE = 0x00;
P07 = !P07;
}
if(intf & 0x04)
{key_num = 2;P0INTE = 0x00;}
if(intf & 0x08)
{key_num = 3;P0INTE = 0x00;}
}
}
578