STC 51单片机自学笔记
作者:互联网
一、准备
硬件问题
- 杜邦线连接 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;
/******************************************************************************/
// P4端口配置
/******************************************************************************/
sfr P4 = 0xc0;
sfr P4M0 = 0xb4;
sfr P4M1 = 0xb3;
/******************************************************************************/
// 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 key1 = P3^6;
sbit key2 = P3^7;
/******************************************************************************/
// 数码管引脚配置
/******************************************************************************/
sbit dig1 = P3^5;//dig1
sbit dig2 = P3^4;//dig2
sbit dig4 = P3^3;
sbit dig3 = P4^0;//dig4
sbit sck = P4^6;
sbit dio = P4^7;
/******************************************************************************/
// LCD1602/LCD12864引脚配置
/******************************************************************************/
sbit EN = P4^3;
sbit RW = P4^2;
sbit RS = P4^1;
sbit PSB = P4^4;
#define lcdPort P2
/******************************************************************************/
// 蜂鸣器引脚配置
/******************************************************************************/
sbit buzz = P4^5;
/******************************************************************************/
// DS18B20引脚配置
/******************************************************************************/
sbit DQ = P0^4;
/******************************************************************************/
// 红外接收引脚配置
/******************************************************************************/
sbit ird = P3^2;
/******************************************************************************/
// DS1302引脚配置
/******************************************************************************/
sbit sclk = P0^7;
sbit Data = P0^6;
sbit ce = P0^5;
/******************************************************************************/
// OLED引脚配置
/******************************************************************************/
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
/******************************************************************************/
/* 叁议电子 */
/* www.ppptalk.com */
// 版本: STC15F2K60S2
// 文件名: delay.c
// 说明: 延时函数
// 编写日期: 2018年4月3日
// 免责声明: 该程序仅用于学习与交流
// (c) PPPTalk All Rights Reserved
/******************************************************************************/
/******************************************************************************/
// 包含头文件
/******************************************************************************/
#include "config.h"
#include "delay.h"
/******************************************************************************/
// 函数名称:Delay15ms
// 输入参数:无
// 输出参数:无
// 函数功能:延时15ms
/******************************************************************************/
void Delay15ms() //@11.0592MHz
{
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; //返回0表示按键按下
}
断码
全称叫七段数码,如下图
七段指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;
//P0 = 0xff;
}
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; //返回0表示按键按下
}
#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; //s4 按下
case 2:led6=~led6;break; //s5 按下
case 3:led7=~led7;break; //s6 按下
case 4:led8=~led8;break; //s7 按下
}
}
}
#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); //等待松开 col_1=1 说明开始松开了
Delay15ms(); //跳过后沿抖动
while(!col_1); //检测是否真的松开
return 1; // 返回1 表示s4按下了
}
}
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) |
//config 数码管引脚配置
sbit dig1 = P3^5;//dig1
sbit dig2 = P3^4;//dig2
sbit dig4 = P3^3;
sbit dig3 = P4^0;
sbit sck = P4^6;
sbit dio = P4^7;
//seg
//函数名称: SEG_ Write_ _Data
//输入参数: dataWrite-写入字节
//输出参数:无
//函数功能:写一个字节,串入并出
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;
}
}
//函数名称:Dig_ Reset
//输入参数:无
//输出参数:无
//函数功能:位控制引脚复位(关闭数码管显示)
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() //@11.0592MHz
{
_nop_(); //_nop_(); 代表运行一个机器周期。如果这个单片机的晶振是12M的,那么这调代码会运行1US;
_nop_();
_nop_();
}
DS1302 寄存器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dmG6uOhb-1626342622143)(E:\文档\坚果云\Typora\51学习.assets\image-20210715153033970.png)]
//DS1302 config 引脚配置
sbit sclk = P0^7;
sbit Data = P0^6; //io
sbit ce = P0^5;
/*
cmdWrite 地址命令 ds1302芯片固定地址配置
函数功能:读一个字节时钟信息
ox81 读秒
0x83 读分
0x85 读小时
*/
uint8 Ds1302_Read_Data(uint8 cmdWrite){
uint8 dataRead,i;
ce = 0; // 上电ce为低电平
sclk = 0; //ce拉高之前保证sclk为低
Delay1us();
ce = 1;// ce为使能
for(i=0;i<8;i++){ //8个上升沿写一个字节 写入命令字
sclk = 0;
Delay1us();
if(cmdWrite&0x01)Data=1;
else Data = 0;
Delay1us();
sclk = 1;
Delay1us();
cmdWrite >>= 1;
}
Data = 1; //释放数据线控制权
//dataRead 根本不需要赋值 左移会移没原先的数据
for(i=0;i<8;i++){ //8个下降沿读取一个字节
dataRead >>= 1;
sclk = 1;
Delay1us();
sclk = 0;
Delay1us();
if(Data)dataRead|=0x80; //先读的数据是最后一位
}
ce = 0; //读写完成 ce拉低 关闭读写
Delay1us();
return dataRead;
}
/*
Ds1302_Write_Data(0x8e,0x00); // 使能打开
Ds1302_Write_Data(0x80,0x50); //设置为50秒
Ds1302_Write_Data(0x82,0x59); // 59分
Ds1302_Write_Data(0x84,0x91); // 11小时
cmdWrite 地址命令 dataWrite 写入数据
函数功能:设置时钟信息
*/
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、蜂鸣器
//config 蜂鸣器引脚配置
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) //@12MHz
{
unsigned char i, j;
while(x--){
// inside 1ms
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引脚为什么会一样?
//config.
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;
- 而且发现led灯与矩阵键盘一起使用会冲突
2.数码管(74HC164 驱动)实验 疑惑
- 数码管 引脚配置全都是 sck dio 一脸懵逼
- main 里面 dig=0; 不应该是在前面赋值选中吗 为什么要赋值为1是reset 0为选中
- 写入数据的时候是如何确定写入位置的 **
3、实时时钟
- 如何数据如何确定位置 时钟写入数据 stc 通过上升沿传入地址命令 通过下降沿数据写入
- 为什么写入 0x50 表示50 里面用的是BCD码:用4位二级制表示一个十进制
- 为什么处理读出的数据要+0x30
标签:P0,引脚,STC,51,单片机,while,sbit,include,Data 来源: https://blog.csdn.net/TY_GYY/article/details/118765169