一、准备
硬件问题
- 杜邦线连接 LED1-LED8 到对应单片机引脚,只要连接程序才会使灯光变化
config.h
#include <reg52.h>
#include <intrins.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
typedef signed char int8;
typedef signed int int16;
typedef signed long int32;
sfr P4 = 0xc0;
sfr P4M0 = 0xb4;
sfr P4M1 = 0xb3;
sbit led1 = P0^0;
sbit led2 = P0^1;
sbit led3 = P0^2;
sbit led4 = P0^3;
sbit led5 = P0^4;
sbit led6 = P0^5;
sbit led7 = P0^6;
sbit led8 = P0^7;
sbit key1 = P3^6;
sbit key2 = P3^7;
sbit dig1 = P3^5;
sbit dig2 = P3^4;
sbit dig4 = P3^3;
sbit dig3 = P4^0;
sbit sck = P4^6;
sbit dio = P4^7;
sbit EN = P4^3;
sbit RW = P4^2;
sbit RS = P4^1;
sbit PSB = P4^4;
#define lcdPort P2
sbit buzz = P4^5;
sbit DQ = P0^4;
sbit ird = P3^2;
sbit sclk = P0^7;
sbit Data = P0^6;
sbit ce = P0^5;
sbit oledSDA = P4^2;
sbit oledSCL = P4^1;
sfr AUXR = 0x8e;
sfr AUXR1 = 0xa2;
sfr S2CON = 0x9a;
sfr T2H = 0xd6;
sfr T2L = 0xd7;
sfr P_SW1 = 0xa2;
sfr P_SW2 = 0xba;
sfr IE2 = 0xaf;
sfr S2BUF = 0x9b;
delay.h
void Delay15ms();
delay.c
#include "config.h"
#include "delay.h"
void Delay15ms()
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 1;
j = 162;
k = 89;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
二、名词解析
管脚(引脚,sbit)
引脚,又叫管脚,英文叫Pin。就是从集成电路(芯片)内部电路引出与外围电路的接线,所有的引脚就构成了这块芯片的接口。引线末端的一段,通过软钎焊使这一段与印制板上的焊盘共同形成焊点。引脚可划分为脚跟(bottom)、脚趾(toe)、脚侧(side)等部分。
sbit 是定义一个引脚。sbit 在c语言中不可视为int之类的变量,声明时就必须指向明确地址 bit Key_Press(sbit key) 这种写法是错误的。
P0,P2 等
PX是一个并行口,有8个引脚,是不能sbit 来定义,可以用 sfr 定义。 P0^0 意义上等价于 P0.0
P0=0xFE
(十六进制)0xFE=(二进制)11111110; p0口有8位,就是把高7为置为1,最后一位置为0.
P0=0; 是将所有的PO 8位设置为低电平
原因
按键开关通常为机械式开关,因为机械触点有弹性,所以当我们按下某一个按键时往往不会马上稳定导通,断开时也不会马上断开,在闭合和断开的瞬间都会伴随弹性抖动。按键按下时的抖动称为前沿抖动,按键松开时的抖动称为后沿抖动,抖动波形如下图所示
软件去抖
软件去抖可利用延时程序进行去抖。由于抖动时间很短,当有按键按下并检测到按下时,对程序进行一小段延时,跳过前沿抖动,再进行一次按键按下检测,若检测到按下则说明确实有按键按下,这也避免了前沿抖动。对于后沿抖动,在检测到确实有按键按下时延时一小段延时,再去检测按键是否被抬起,检测到抬起则一次按键的检测完毕。
bit Key1_Press(void){
bit flag = 1;
key1 = 1;
if(!key1){
Delay15ms();
if(!key1){
while(!key1);
Delay15ms();
while(!key1);
flag = 0;
}
}
return flag;
}
断码
全称叫七段数码,如下图
七段指a,b,c,d,e,f,g段位.一段位实际是一个发光二极管,用这7个二极管组合能组成0-9,a-f等等数字或16进制数,所以叫七段数码,数码连接的共公端不同,就有共阳与共阴之分.有的为了显示小数点,又在后面再加了一个发光二极管,就是dp段位,这样就能很好的显示数字。
三、参考代码练习
1、LED灯闪亮
LED 实验过程中需要采用杜邦线连接 LED1-LED8 到对应单片机引脚,参考程序中使用的是 P0 端口
#include "config.h"
#include "delay.h"
int main()
{
while(1){
led1 = 0;
Delay15ms();
led1 = 1;
led2 = 0;
Delay15ms();
led2 = 1;
}
return 0;
}
2、独立按键实验
当按下 S2 时,LED1 状态改变,当按下 S3 时,LED2 状态改变。
bit Key1_Press(void){
bit flag = 1;
key1 = 1;
if(!key1){
Delay15ms();
if(!key1){
while(!key1);
Delay15ms();
while(!key1);
flag = 0;
}
}
return flag;
}
#include "config.h"
#include "delay.h"
#include "key.h"
int main(void){
led1 = 0;
led2 = 0;
while(1){
if(!Key1_Press())led1=~led1;
if(!Key2_Press())led2=~led2;
}
}
3、矩阵键盘
在config中加入
sbit row_1 = P0^0;
sbit row_2 = P0^1;
sbit col_1 = P0^2;
sbit col_2 = P0^3;
LED用的是5~6
#include "config.h"
#include "delay.h"
#include "keyboard.h"
int main(void){
led5 = 1;
led6 = 1;
led7 = 1;
led8 = 1;
while(1){
switch (Keyboard_Press()){
case 0:break;
case 1:led5=~led5;break;
case 2:led6=~led6;break;
case 3:led7=~led7;break;
case 4:led8=~led8;break;
}
}
}
#include "config.h"
#include "keyboard.h"
#include "delay.h"
uint8 Keyboard_Press(void){
col_1 = 1;
col_2 = 1;
row_1 = 0;
row_2 = 1;
if(!col_1){
Delay15ms();
if(!col_1){
while(!col_1);
Delay15ms();
while(!col_1);
return 1;
}
}
if(!col_2){
Delay15ms();
if(!col_2){
while(!col_2);
Delay15ms();
while(!col_2);
return 2;
}
}
row_1 = 1;
row_2 = 0;
if(!col_1){
Delay15ms();
if(!col_1){
while(!col_1);
Delay15ms();
while(!col_1);
return 3;
}
}
if(!col_2){
Delay15ms();
if(!col_2){
while(!col_2);
Delay15ms();
while(!col_2);
return 4;
}
}
return 0;
}
4、数码管(74HC164 驱动)实验
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wCW4zWbV-1626342622134)(E:\文档\坚果云\Typora\51学习.assets\image-20210714102016608.png)]
一个数码管如上图所示 假如 数码管共阳极 即1不亮0亮 那么输入断码0xFF(1111 1111)表示为 什么都不显示
数码管共阳极 数字转换如下,segNum为
uint8 code segNum[11] = {0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09};
十进制数字 | 16进制数据 |
---|
1. (注意有点) | 0x9e(1001 1110) | 1 | 0x9f(1001 1111) | 2 | 0x25(0010 0101) | 3 | 0x0d(0000 1101) | 4 | 0x99(1001 1001) | 5 | 0x49(0100 1001) | 6 | 0x41(0100 0001) | 7 | 0x1f(0001 1111) | 8 | 0x01(0000 0001) | 9 | 0x09(0000 1001) | 0 | 0x03(0000 0011) |
sbit dig1 = P3^5;
sbit dig2 = P3^4;
sbit dig4 = P3^3;
sbit dig3 = P4^0;
sbit sck = P4^6;
sbit dio = P4^7;
void SEG_Write_Data(uint8 dataWrite){
uint8 i;
for(i=0;i<8;i++){
if(dataWrite&0x01)dio=1;
else dio=0;
sck = 0;
sck = 1;
dataWrite >>= 1;
}
}
void Dig_Reset(void){
dig1 = 1;
dig2 = 1;
dig3 = 1;
dig4 = 1;
}
主函数配置 (注意这个板子没有解码器一共四个 对应申明sbit即可控制是否选中 选中的意思表示开共阳极的那一段供电)在main中给digX赋值0;表示选中第X个数码管
#include "config.h"
#include "delay.h"
#include "seg.h"
uint8 code segTable[4] = {0x9e,0x25,0x0d,0x99};
int main(void){
uint8 i;
while(1){
for(i=0;i<4;i++) {
Dig_Reset();
SEG_Write_Data(segTable[i]);
if(i==0)dig1=0;
if(i==1)dig2=0;
if(i==2)dig3=0;
if(i==3)dig4=0;
}
}
}
10、DS1302 实时时钟
delay新增
void Delay1us()
{
_nop_();
_nop_();
_nop_();
}
DS1302 寄存器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dmG6uOhb-1626342622143)(E:\文档\坚果云\Typora\51学习.assets\image-20210715153033970.png)]
sbit sclk = P0^7;
sbit Data = P0^6;
sbit ce = P0^5;
uint8 Ds1302_Read_Data(uint8 cmdWrite){
uint8 dataRead,i;
ce = 0;
sclk = 0;
Delay1us();
ce = 1;
for(i=0;i<8;i++){
sclk = 0;
Delay1us();
if(cmdWrite&0x01)Data=1;
else Data = 0;
Delay1us();
sclk = 1;
Delay1us();
cmdWrite >>= 1;
}
Data = 1;
for(i=0;i<8;i++){
dataRead >>= 1;
sclk = 1;
Delay1us();
sclk = 0;
Delay1us();
if(Data)dataRead|=0x80;
}
ce = 0;
Delay1us();
return dataRead;
}
void Ds1302_Write_Data(uint8 cmdWrite,uint8 dataWrite){
uint8 i;
ce = 0;
sclk = 0;
Delay1us();
ce = 1;
for(i=0;i<8;i++){
sclk = 0;
Delay1us();
if(cmdWrite&0x01)Data=1;
else Data = 0;
Delay1us();
sclk = 1;
Delay1us();
cmdWrite >>= 1;
}
for(i=0;i<8;i++){
sclk = 0;
Delay1us();
if(dataWrite&0x01)Data=1;
else Data = 0;
Delay1us();
sclk = 1;
Delay1us();
dataWrite >>= 1;
}
sclk = 0;
ce = 0;
Delay1us();
}
#include "config.h"
#include "delay.h"
#include "seg.h"
uint8 code segNum[11] = {0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09};
int main(void){
uint8 dataSecond,dataMin,dataHour, dataCell,showCell;
uint8 showData[10]={'0','0','0','0','0','0','0','0','0','0'},i;
Ds1302_Write_Data(0x8e,0x00);
Ds1302_Write_Data(0x80,0x50);
Ds1302_Write_Data(0x82,0x59);
Ds1302_Write_Data(0x84,0x91);
while(1){
dataSecond = Ds1302_Read_Data(0x81);
dataMin = Ds1302_Read_Data(0x83);
dataHour = Ds1302_Read_Data(0x85);
showData[0] = ((dataHour >> 4)&0x01) + 0x30;
showData[1] = (dataHour & 0x0f) + 0x30;
showData[2] = ((dataMin & 0x7f) >> 4) + 0x30;
showData[3] = (dataMin & 0x0f) + 0x30;
showData[4] = ((dataSecond & 0x7f) >> 4) + 0x30;
showData[5] = (dataSecond & 0x0f) + 0x30;
for(i=0;i<4;i++){
Dig_Reset();
dataCell=showData[i+2]-'0';
if(dataCell<0&&dataCell>9)
dataCell=segNum[0];
showCell=segNum[dataCell];
if(i==1){
showCell-=1;
}
SEG_Write_Data(showCell);
if(i==0)dig1=0;
if(i==1)dig2=0;
if(i==2)dig3=0;
if(i==3)dig4=0;
delayXms(1);
}
}
}
11、蜂鸣器
sbit buzz = P4^5;
#include "config.h"
#include "delay.h"
void buzzOn(void){
buzz = 0;
}
void buzzOff(void){
buzz = 1;
}
int main(void){
uint8 i;
while(1){
buzzon();
delayXms(5);
buzzoff();
delayXms(5);
}
}
自定义delay
void DelayXms(int x)
{
unsigned char i, j;
while(x--){
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
四、报错分析与解决
*** WARNING L7: MODULE NAME NOT UNIQUE *** WARNING L2: REFERENCE MADE TO UNRESOLVED EXTERNAL
建工程的时候添加了STARTUP.A51文件。如果删除这个文件,依旧不能解决,只能重新创建项目(不要创建startup文件)才能解决,原因未知。
如果一直找不出原因 全部保存关闭软件然后重新打开!!!
五、疑惑问题
1. 矩阵引脚 LED引脚为什么会一样?
sbit led1 = P0^0;
sbit led2 = P0^1;
sbit led3 = P0^2;
sbit led4 = P0^3;
sbit led5 = P0^4;
sbit led6 = P0^5;
sbit led7 = P0^6;
sbit led8 = P0^7;
sbit row_1 = P0^0;
sbit row_2 = P0^1;
sbit col_1 = P0^2;
sbit col_2 = P0^3;
2.数码管(74HC164 驱动)实验 疑惑
- 数码管 引脚配置全都是 sck dio 一脸懵逼
- main 里面 dig=0; 不应该是在前面赋值选中吗 为什么要赋值为1是reset 0为选中
- 写入数据的时候是如何确定写入位置的 **
3、实时时钟
- 如何数据如何确定位置 时钟写入数据 stc 通过上升沿传入地址命令 通过下降沿数据写入
- 为什么写入 0x50 表示50 里面用的是BCD码:用4位二级制表示一个十进制
- 为什么处理读出的数据要+0x30
|