51代码集合(之前一些杂乱无章的写法)
- 动态显示数码管(本次实验的目标是让八位数码管输出01234567,无小数点,且稳定保持输出)
- #include "reg5h" //包含头文件reg5h
- sbit c = P2^2;
- sbit b = P2^3;
- sbit a = P2^4; //对于a,b,c不能使用宏定义赋值,是一个二进制端口使用sbit关键字赋值;
- #define D P0 //宏定义端口P0为D,在后面直接对D进行数组赋值
- unsigned char gongyin[8]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07};//给出七段数码管的字形0~7的编码
- void delay(unsigned int n)
- {
- while(n--);
- }
- void array_dynamicled()
- {
- unsigned char i =0 ;//每次进入这个函数首先将i置0
- for(i=0;i<8;i++)
- {
- switch(i)//进行位选
- {
- case 0: a=1;b=1;c=1;break;
- case 1: a=1;b=1;c=0;break;
- case 2: a=1;b=0;c=1;break;
- case 3: a=1;b=0;c=0;break;
- case 4: a=0;b=1;c=1;break;
- case 5: a=0;b=1;c=0;break;
- case 6: a=0;b=0;c=1;break;
- case 7: a=0;b=0;c=0;break;
- }
- D = gongyin[i];//通过数组进行段选
- delay(100); //经过测试参数为300的时候约为人眼能够分辨与不能分辨的临界值,约为0.02s,如果没有delay函数,数码管显示会变暗,delay使得输出稳定
- D = 0x00; //防止通过P2^5输入脉冲信号导致蜂鸣器发声,消音
- }
- }
- void main()
- {
- while(1)
- {
- array_dynamicled();//进入主函数,只要工作正常则一直循环
- }
- }
2.独立按键(当按下K1时,D1亮,再次按下K1时,D1熄灭)
实验使用的是按键开关,使用时按下开关,开关接通,松开手的时候,开关断开.
原理:管脚距离长的默认是导通状态,距离短的默认是断开状态.当按下按键时,初始导通断开,初始断开变为导通.(一般使用的是机械弹性开关)
机械开关:按键开关在闭合的时候不会马上接通,在断开的时候也不会一下子断开,类似于电容充电充满和放电放完.所以在闭合和断开的时候通常会伴随一连串的抖动,抖动时间的长短是由不同按键的机械特性来决定的,一般是5~10ms.
按键闭合的时间长短是由操作人员的按键动作来决定的,一般是零点几秒到几秒.按键抖动可能会被误认为是读了多次,为了确保CPU对一次按键就是仅做一次处理,要进行消除抖动(消抖).
按键消抖通常有两种方式.一种是硬件消抖,一种是软件消抖.通常更为简单的方法是软件消抖.实验板也用软件消抖.
何为软件消抖?比如说一个消抖的程序是:按键按下之后,延时10ms再读取按键的状态,如果按键还是处于按下的状态,那么说明按键已经被按下.硬件消抖主要由rs触发器和电容滤波两种方法.rs触发器消抖的原理是:当按键按下时,RS触发器马上就翻转,从而避免了抖动的影响.
单片机是怎么消除抖动的?
软件设计
- 先设置IO口为高电平,一般IO口设有上拉电阻,默认IO为高电平.
- 读取IO口是否有按键按下.
- 如果IO口为低电平,且过了十个毫秒后读取依然为低电平,则说明确实有按键按下.
- 这时,根据按键控制程序来进行相应的操作.
(疑似3.0和3.1的位置接反了??)
独立按键的电路结构如上图所示,各个按键的一个管脚都是接地,另外的一个管脚分别连接到P31,P30,P32,P33.(K1,K2,K3,K4)
单片机的IO口当然是既可以作为输入也可以作为输出来使用.当作检测按键是输入的功能,
硬件设计
- K1按键
- D1指示灯
K1-P3^1
K2-P3^0
K3-P3^2
K4-P3^2
1000~=10ms(延时程序)
关键点:LED1被翻转,或者通过P2^0来控制(低电平点亮).
#include "reg52.h"
sbit K1=P3^1;//由于一个公共端是接地的,及要考虑是不是另外的三个按键按下导致的LED亮了,在下文程序中加以表示(先不写这段代码来看一下结果)
sbit K2=P3^0;
sbit K3=P3^2;
sbit K4=P3^3;
sbit LED1=P2^0;
//#define u8 unsigned char 这种定义是错误的
//define u16 unsigned int*/ //同上,不能用宏定义定义一个数据类型
typedef unsigned char u8;
typedef unsigned int u16; //无等号,有分号,与#define类似(但是有分号)
//先写出延时函数和按键检测函数,然后进入主函数
void delay(u16 n)
{
while(n--);
}
u16 monitor(u16 n)
{ if(n==1)
{
return 1;
}
else
if(K1==0) //开始写入检测函数
{
delay(1000);//在这里写void声明函数原型会报错,函数在前已经声明.
if(K1==0)
{
return K1;
}
else
{
return K1; //这里应该还是return K1,逻辑错误了.
}
}
else
return K1; //not every exit path returns a value(不是所有的路径都有返回值) 如果不写这一行,在自启动的时候电路进入未知值
}
void main()
{
while(1)
{
//LED1=monitor(); //此处不应该使用赋值语句,应该让led灯的状态翻转或者通过改变P2^0的电平
if (monitor(K1)==0)
{
LED1 = !LED1;
}
}
}


#include "reg52.h"
sbit K1=P3^1;//由于一个公共端是接地的,及要考虑是不是另外的三个按键按下导致的LED亮了,在下文程序中加以表示(先不写这段代码来看一下结果)
sbit K2=P3^0;
sbit K3=P3^2;
sbit K4=P3^3;
sbit LED1=P2^0;
//#define u8 unsigned char 这种定义是错误的
//define u16 unsigned int*/ //同上,不能用宏定义定义一个数据类型
typedef unsigned char u8;
typedef unsigned int u16; //无等号,有分号,与#define类似(但是有分号)
//先写出延时函数和按键检测函数,然后进入主函数
void delay(u16 n)
{
while(n--);
}
u16 monitor()
{
static u16 switch1 =0;
if(!switch1&&K1==0) //开始写入检测函数
{
delay(1000);//在这里写void声明函数原型会报错,函数在前已经声明.
switch1=1;//标记已经按下,后续构成环
if(K1==0)
{
return 0;
}
}
else if(switch1&&K1==0)
{
switch1=0;
return 0;
}
}
void main()
{
while(1)
{
//LED1=monitor(); //此处不应该使用赋值语句,应该让led灯的状态翻转或者通过改变P2^0的电平
if (!monitor())
{
LED1 = !LED1;
}
}
}


错误说明:在写这个程序的时候,出现了” not every exit path returns a value()”(不是所有的退出路径都有返回值),也就是说在写if…return…else最后在条件之外一定要加上返回语句,不然在某些情况下的返回值是不确定的,也就是函数原型中声明的有返回值但是没有返回值的,有时候会自动选择离出口(结束)最近的一个return…语句.
3.矩阵按键
实验板上用的是4*4矩阵键盘,将16个按键排列成4行4列. Line scanning and reverse method.
矩阵键盘两端都与单片机IO相连,需要在检测时送出低电平,检测方法有行列扫描和线翻转法.

实验目的:矩阵按键S1-S16按下后,数码管显示0~F.
17是第一行,13是第一列.
源代码:
#include "reg52.h"
#define smg_port P0
#define matrix_port P1
typedef unsigned char u8;
typedef unsigned int u16;
u8 smg_code[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//先写出延时函数和按键扫描函数,然后进入主函数循环
/****************************
*函数名 : delay
*函数功能: 延时,参数为100时,大概是1ms,常用于消抖或者使数据传输稳定,或者说参数为1时代表10us.
*输入: ten_us
*输出: 无
*********************************************/
void delay(u16 ten_us)
{
while(ten_us--);
}
/********************************
*函数名 : scanner
*函数功能: 行列式扫描或者是线翻转式扫描
*输入: void
*输出: 1.key_value输出为0,没有按键按下;
2.key_value输出为1-16,对应的是S1-S16键
3.输出的值进而在下一个函数中转给数码管端口数组的下标
************************************/
u8 scanner(void)
{
static u8 key_value = 0; //设置静态变量key_value,后续方便连续操作.
//11110111是让第一列赋值为1,低电平有效,转换为十六进制就是0xf7(H);
matrix_port = 0xf7; //只有第一列有效,其余全为1;
if(matrix_port!=0xf7)
{
delay(1000);//消除抖动
switch(matrix_port)
{
case 0x77: key_value=1;break;
case 0xb7: key_value=5;break;
case 0xd7: key_value=9;break;
case 0xe7: key_value=13;break;
}
}
while(matrix_port!=0xf7);//等待按键松开
//开始第二段的编写
matrix_port = 0xfb; //只有第一列有效,其余全为1;
if(matrix_port!=0xfb)
{
delay(1000);//消除抖动
switch(matrix_port)
{
case 0x7b: key_value=2;break;
case 0xbb: key_value=6;break;
case 0xdb: key_value=10;break;
case 0xeb: key_value=14;break;
}
}
while(matrix_port!=0xfb);//等待按键松开
//开始第三段的编写
matrix_port = 0xfd; //只有第一列有效,其余全为1;
if(matrix_port!=0xfd)
{
delay(1000);//消除抖动
switch(matrix_port)
{
case 0x7d: key_value=3;break;
case 0xbd: key_value=7;break;
case 0xdd: key_value=11;break;
case 0xed: key_value=15;break;
}
}
while(matrix_port!=0xfd);//等待按键松开
//开始第四段的编写
matrix_port = 0xfe; //只有第一列有效,其余全为1;
if(matrix_port!=0xfe)
{
delay(1000);//消除抖动
switch(matrix_port)
{
case 0x7e: key_value=4;break;
case 0xbe: key_value=8;break;
case 0xde: key_value=12;break;
case 0xee: key_value=16;break;
}
}
while(matrix_port!=0xfe);//等待按键松开
//注意:最后应当有返回值!!!
return key_value;
}
//进入主函数
void main()
{
u8 key=0;
while(1)
{
key = scanner();
if(key!=0)
{
smg_port = smg_code[key-1];
}
}
}




(本次实验代码主要使用了行列扫描的方式来作算法,线翻转有待进一步学习.)

逻辑障碍:如果要用八位数码管显示时间,其中的秒位必须是一秒一秒的跳动,但是位选信号在一个时间内只能选择一个位,在秒位上延时时间过长导致看起来只有秒位是亮着的(相对来说).
在上次的实验中,看上去静止的原因是每一位亮的时间都很短,10ms左右,视觉暂留.在此基础上好像不可能完成闹钟的实现.
解决方案:使用定时器.
3.滚动显示(一排一排的显示led灯)
1.注意到u8的上限是255.
2.数据在低电平和高电平转换后有必要延时一段时间来作为稳定.10us
3.滚动一行时间500ms.
4.数组定义时应该完整定义,不然会警告太多的初始化.
5.用for循环嵌套来写u8的延时,最后调用参数为u16.
6.数据串行输入hc595先传输高位>>7,再让低位前进到高位<<=1.
7.一个字节的数据传输完之后才由移位寄存器传输到存储寄存器当中.
8.在存储寄存器输出之前,先将该寄存器和移位寄存器的数值清零.
4.led点阵(显示左上方led灯亮,后续显示汉字等)
问题一:能够直接把对应的行拉高电平,然后对应的列接低电平然后亮灯吗?
SER RCLK SRCLK
3.4 3.5 3.6
只是点亮左上角一个led灯当然简单,只需要第一行接高电平,第一列接低电平就行了.
之后根据74HC595的通信时序来传递数据,显示原理与动态数码管相似,24ms.
5.led点阵动态显示(显示汉字等)
由于led点阵是共阳共阴,在操作不同的行列时,不能点亮想要点亮的led.动态数码管显示的原理与点阵动态显示的原理是相似的,也就是说只需要在循环中写入两个数组,一个是行数组,一个是列数组,然后进行赋值即可.
另外在本次实验中的问题:RCLK似乎是下降沿触发的时钟信号,在时钟下降沿(10us)的过程中输出数据.(存储寄存器时钟信号).(在厂家给的说明书中RCLK是上升沿触发的信号)
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
