STC8H8K系列汇编和C51实战——实现跑马灯(51版)
STC8H8K系列汇编和C51实战——实现跑马灯(汇编版)
STC8H8K系列汇编和C51实战——实现键控不同方式数码管动态显示(C51版与汇编版)
STC8H8K系列汇编和C51实战——开关控制定时器秒表(C51版)
STC8H8K系列汇编和C51实战——开关控制定时器秒表(汇编版)
STC8H8K系列汇编和C51实战——双中断控制定时器流水灯
STC8H8K系列汇编和C51实战——双中断加减计数器
STC8H8K系列汇编和C51实战——简易频率计
STC8H8K系列汇编和C51实战——秒倒计时器(汇编版)
STC8H8K系列汇编和C51实战——秒倒计时器(51版)
STC8H8K系列汇编和C51实战——秒倒计时器(可自行设定初值)(51版)
STC8H8K系列汇编和C51实战——按键允许按键计数(51版)
STC8H8K系列汇编和C51实战——按键允许按键计数(汇编版)
STC8H8K系列汇编和C51实战——按键允许按键计数(定时器去抖动51版)
STC8H8K系列汇编和C51实战——按键允许按键计数(利用下降沿中断控制)
STC8H8K系列汇编和C51实战——计算机串口控制单片机LED
STC8H8K系列汇编和C51实战——串口发送菜单界面选择不同功能
个人对这个实验的汇编部分不太熟悉,逻辑上面可能不太流畅,请各位见谅。
在Keil μVision2集成开发环境, 分别用C51和MCS-51汇编语言编程,在实验箱上用SW17和SW18(分别对应P3.2和P3.3)两个独立按键状态的四种组合控制实验箱上数码管以四种不同流水方式滚动显示信息:
1) 模式0:SW17和SW18都不按下, 8个数码管从左到右固定显示数字1-8;
2) 模式1:SW17按下,SW18不按下, 8个数码管从左到右依次逐步显示数字1-8, 即1,2, 3,…从左到右是逐步显示出来的,间隔为0.1秒, 直到1-8全部显示后重复这个该显示过程;
3) 模式2:SW17不按下,SW18按下, 8个数码管从右到左依次逐步显示数字1-8, 方式类似模式1,只是方向不同;
4) 模式3:SW17和SW18同时按下, 从最中间两个数码管逐步扩展显示数字2,直到显示8个2,然后重新从中间开始重复以上显示过程。
// 文件名称: 实验三51部分
//作者: 不知何人
// 完成日期: 2022.4.16
//内容摘要: 无
//注意: 无
#include
void Delay100ms() //@24.000MHz
{
unsigned char i, j, k;
i = 10;
j = 31;
k = 147;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay10ms() //@24.000MHz
{
unsigned char i, j, k;
i = 2;
j = 56;
k = 172;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay1ms() //@24.000MHz
{
unsigned char i, j;
i = 24;
j = 85;
do
{
while (--j);
} while (--i);
}
/************* 本地常量声明 **************/
u8 code t_display[]={ //标准字库
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71}; //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1
u8 code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //位码
u8 code T_COM1[]={0x18,0x3C,0x7E,0xFF}; //位码
void Nixie1() //数码管显示函数1
{
u8 i;
for(i = 0; i < 8; i++)
{
P7 = ~T_COM[i];
P6 = ~t_display[i + 1];
Delay1ms();
P6 = 0xFF;
}
}
void Nixie2() //数码管显示函数2
{
u8 i;
for(i = 0; i < 8; i++)
{
P7 = ~T_COM[i];
P6 = ~t_display[i + 1];
Delay100ms();
P6 = 0xFF;
}
}
void Nixie3()//数码管显示函数3
{
u8 i;
for(i = 8; i > 0; i--)
{
P7 = ~T_COM[i - 1];
P6 = ~t_display[i];
Delay100ms();
P6 = 0xFF;
}
}
void Nixie4()//数码管显示函数4
{
u8 i;
for(i = 0; i < 4; i++)
{
P7 = ~T_COM1[i];
P6 = ~t_display[2];
Delay100ms();
P6 = 0xFF;
}
}
void gpio() //gpio初始化为准双向口,刚开始除了P30,P31其他均为高阻态
{
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; //设置为准双向口
}
u8 key = -1;
void ChooseKey()//通过按键状态确定不同模式
{
if(P32 != 0 && P33 != 0)
{
Delay10ms(); //消抖
if(P32 != 0 && P33 != 0)
{
key = 0;
}
}
else if(P32 == 0 && P33 != 0)
{
Delay10ms();
if(P32 == 0 && P33 != 0)
{
key = 1;
}
}
else if(P32 != 0 && P33 == 0)
{
Delay10ms();
if(P32 != 0 && P33 == 0)
{
key = 2;
}
}
else if(P32 == 0 && P33 == 0)
{
Delay10ms();
if(P32 == 0 && P33 == 0)
{
key = 3;
}
}
switch(key)//对应模式的数码管显示
{
case 0: Nixie1();break;
case 1: Nixie2();break;
case 2: Nixie3();break;
case 3: Nixie4();break;
}
}
void main()
{
gpio();
while(1)
{
ChooseKey();
}
}
// 文件名称: 实验三汇编部分
//作者: 不知何人
// 完成日期: 2022.4.16
//内容摘要: 无
//注意: 无
NIXIE:
MOV R2, #8
MOV DPTR, #T_Display1
MOV R3, #0FEH
NIXIE_LOOP0:
JNB P3.2, NIXIE_LOOP1
JNB P3.3, NIXIE_LOOP2
MOV P7,#0FFH
MOV A,@R0
INC R0
MOVC A, @A+DPTR
MOV P6, A
MOV A, R3
MOV P7, A ;从第1位-8位数码管依次导通
RL A ;循环左移
MOV R3, A ;下一次P7口的值给R3,下次赋值给P7
LCALL DELAY1MS ;消影,避免上一个数字视觉残留
DJNZ R2, NIXIE_LOOP0 ;点亮一轮以后退出
RET
NIXIE_LOOP1:
JNB P3.3, NIXIE_LOOP3
JB P3.2, NIXIE_LOOP0
LCALL DELAY5MS
JNB P3.3, NIXIE_LOOP3
JB P3.2, NIXIE_LOOP0
MOV P7,#0FFH
MOV A,@R0
INC R0
MOV DPTR, #T_Display2
MOVC A, @A+DPTR
MOV P6, A
MOV A, R3
MOV P7, A ;从第1位-8位数码管依次导通
RR A ;循环右移
MOV R3, A ;下一次P7口的值给R4,下次赋值给P7
LCALL DELAY100MS
DJNZ R2, NIXIE_LOOP1 ;点亮一轮以后退出
RET
NIXIE_LOOP2:
JB P3.3, NIXIE_LOOP0
JNB P3.2, NIXIE_LOOP3
LCALL DELAY5MS
JB P3.3, NIXIE_LOOP0
JNB P3.2, NIXIE_LOOP3
MOV P7,#0FFH
MOV A,@R0
INC R0
MOV DPTR, #T_Display3
MOVC A, @A+DPTR
MOV P6, A
MOV A, R3
MOV P7, A ;从第1位-8位数码管依次导通
RL A ;循环左移
MOV R3, A ;下一次P7口的值给R3,下次赋值给P7
LCALL DELAY100MS
DJNZ R2, NIXIE_LOOP2 ;每按个点亮一轮以后退出
RET
NIXIE_LOOP3:
JB P3.2, NIXIE_LOOP2
JB P3.3, NIXIE_LOOP1
INC A
MOV P7,#0FFH
MOV P6,#0A4H
MOV P7, #0E7H
LCALL DELAY1000MS
JB P3.2, NIXIE_LOOP2
JB P3.3, NIXIE_LOOP1
MOV P7, #0C3H
LCALL DELAY1000MS
JB P3.2, NIXIE_LOOP2
JB P3.3, NIXIE_LOOP1
MOV P7, #81H
LCALL DELAY1000MS
JB P3.2, NIXIE_LOOP2
JB P3.3, NIXIE_LOOP1
MOV P7, #00H
LCALL DELAY1000MS
RET
T_Display1:
DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H
T_Display2:
DB 0C0H,0F8H,82H,92H,99H,0B0H,0A4H,0F9H,80H
T_Display3:
DB 0C0H,80H,0F8H,82H,92H,99H,0B0H,0A4H,0F9H
DELAY1MS: ;@24.000MHz
PUSH 30H
PUSH 31H
MOV 30H,#32
MOV 31H,#39
NEXT:
DJNZ 31H,NEXT
DJNZ 30H,NEXT
POP 31H
POP 30H
RET
DELAY100MS: ;@24.000MHz
NOP
NOP
PUSH 30H
PUSH 31H
PUSH 32H
MOV 30H,#13
MOV 31H,#45
MOV 32H,#212
NEXT1:
DJNZ 32H,NEXT1
DJNZ 31H,NEXT1
DJNZ 30H,NEXT1
POP 32H
POP 31H
POP 30H
RET
DELAY1000MS: ;@24.000MHz
NOP
NOP
PUSH 30H
PUSH 31H
PUSH 32H
MOV 30H,#122
MOV 31H,#193
MOV 32H,#126
NEXT2:
DJNZ 32H,NEXT2
DJNZ 31H,NEXT2
DJNZ 30H,NEXT2
POP 32H
POP 31H
POP 30H
RET
DELAY5MS: ;@24.000MHz
NOP
PUSH 30H
PUSH 31H
MOV 30H,#156
MOV 31H,#212
NEXT3:
DJNZ 31H,NEXT3
DJNZ 30H,NEXT3
POP 31H
POP 30H
RET
数码管的使用,关键在于闪烁的频率,频率越快,自然越不晃眼(不像手机的OLED屏幕哈哈哈),当频率越慢的时候,就显示出了流水灯的效果,频率越快就显示是静态的效果了。而想要精确掌握数码管,我们需要很熟练的使用位选段选,这样才能玩出花来。
对汇编不熟悉的朋友(比如我)刚开始会对第二段代码理解有点困难,其实有C语言基础的初学者在大致知道各个指令的功能之后,只需要再查一下if、for、while等语句在汇编中的表示方法就可以很快领悟了。汇编麻烦的是语句太多,过于繁琐,但是效率提升高,至少优化20%-30%,多用于驱动程序处。
主页还有许多汇编、C51、以及Proteus源码和原理图等,这些天就会上传matlab以及Python人工智能算法的代码和资源,现在开始也会陆续有数字图像处理以及单片机作品的展示,全部开源,欢迎各位来看!!!
非常感谢各位观看!!!