C语言:51单片机看这一篇就够了

Posted Lion King

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言:51单片机看这一篇就够了相关的知识,希望对你有一定的参考价值。

前言

本篇文章属于学习笔记,来源于B站教学视频,相关代码工程请从源地址自行下载。这位Up讲解得很好,适合同学们一起学习,在这里推荐给大家。本文为个人学习笔记,只能做参考,细节方面建议观看视频,肯定受益匪浅。

51单片机入门教程-2020版 程序全程纯手打 从零开始入门_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Mb411e7re?p=1

一、环境搭建

1、开发软件Keil5C51

2、烧录软件stc-isp

3、普中51单片机开发板

二、单片机介绍

1、单片机(Micro Controller Unit ,即MCU)

2、本篇所使用的单片机为STC89C52单片机

所属系列为8051,即51单片机。8051最开始指在80年代生产的8051内核的单片机。后延伸为只要是8051内核的单片机,都统称为51单片机。

3、51单片机命名规则

4、51单片机结构

三、单片机实操一:点亮一个LED

1、打开STC-ISP添加芯片包到开发环境

2、创建工程

 

3、创建文件

 4、LED的硬件原理图

在下面的图中,我们可以看到LED最终连上了单片机的管脚。而单片机需要通过CPU控制寄存器的值,进而通过驱动器加大控制力度,由控制电路输出高低电平(对应寄存器1/0)。因此,程序需要在对应的寄存器上写1或0,即可控制LED的亮灭。

5、编写程序

根据硬件原理图和寄存器定义,来对操作寄存器地址,实现灯的点亮

#include <STC89C5xRC.H>

void main()

	P2 = 0xFE; //1111 1110

6、实验过程与代码解释

(1)点击F7编译单个文件,编译失败,给出P2不认识的提示

(2)添加H文件,继续编译,编译通过 ,说明头文件定义了P2

(3)为什么控制的是P2?因为硬件原理图以及头文件的定义,拉低电平即可点亮一盏灯!

7、生成文件,下载到板子上,重新上电之后可运行该程序

 

 

 

 

四、单片机实操二:LED闪烁

1、在指定路径下创建工程并添加新文件

2、通过STC-ISP拷贝延时代码

 3、编写程序

加入延时,方便观察灯的闪烁

#include <STC89C5xRC.H>
#include <INTRINS.H>

void Delay500ms()		//@12.000MHz

	unsigned char i, j, k;

	_nop_();    //An empty function, from INTRINS.H
	i = 4;
	j = 205;
	k = 187;
	do
	
		do
		
			while (--k);
		 while (--j);
	 while (--i);


void main()

	P2=0xFE;
	Delay500ms();
	P2=0xFF;
	Delay500ms();

4、实验过程

 

五、单片机实操三:LED流水灯

1、在指定路径下创建工程并添加新文件

2、编写程序

让LED循环点亮,像流水一样

#include <STC89C5xRC.H>
#include <INTRINS.H>

void Delay500ms()		//@12.000MHz

	unsigned char i, j, k;

	_nop_();
	i = 4;
	j = 205;
	k = 187;
	do
	
		do
		
			while (--k);
		 while (--j);
	 while (--i);


void main()

    while(1)
    
	P2=0xFE;  //1111 1110
	Delay500ms();
	P2=0xFD;  //1111 1101
	Delay500ms();
	P2=0xFB;  //1111 1011
	Delay500ms();
	P2=0xF7;  //1111 0111
	Delay500ms();
	P2=0xEF;  //1110 1111
	Delay500ms();
	P2=0xDF;  //1101 1111
	Delay500ms();
	P2=0xBF;  //1011 1111
	Delay500ms();
	P2=0x7F;  //0111 1111
    Delay500ms();
    

六、单片机实操四:LED流水灯Plus

1、在指定路径下创建工程并添加新文件

2、编写程序

将延时函数参数化。

#include <STC89C5xRC.H>
#include <INTRINS.H>

void Delayxms(unsigned int xms)		//@12.000MHz

	unsigned char i, j;
	while(xms)
	
	i = 2;
	j = 239;
	do
	
		while (--j);
	 while (--i);
		xms--;  //xms=xms-1
	



void main()

	while(1)
	
	P2=0xFE;  //1111 1110
	Delayxms(500);
	P2=0xFD;  //1111 1101
	Delayxms(500);
	P2=0xFB;  //1111 1011
	Delayxms(500);
	P2=0xF7;  //1111 0111
	Delayxms(500);
	P2=0xEF;  //1110 1111
	Delayxms(500);
	P2=0xDF;  //1101 1111
	Delayxms(500);
	P2=0xBF;  //1011 1111
	Delayxms(500);
	P2=0x7F;  //0111 1111
    Delayxms(500);
	

3、51单片机的数据类型

我们在上面的程序中使用到了数据类型unsigned int xms,即xms在单片机中能表示0~65535

七、单片机实操五:独立按键控制LED灯亮灭

1、在指定路径下创建工程并添加新文件

2、独立按键原理图

3、编写程序

按下按键亮灯,松开按键灭灯。

#include <STC89C5xRC.H>

void main()

	
	while(1)
	
		if(P30==0)
		
			P20=0;
		
		else
		
			P20=1;
		
	

4、51单片机数据运算

上述代码中,我们使用到了==这个运算符,表示等于。

 5、51单片机基本语句

上述程序用到了if语句,通过判断按键的动作来实现灯的亮灭

 6、注意事项

程序写的是P30独立按键,根据原理图,需要按下K2才能点亮第一盏灯。(原理图设计者并没有按照顺序一一对应按键,这是设计者埋下的小坑)

P30是H文件中定义的,如果是其他H文件可能没有或者用另一个变量表示,这个时候需要你自己去写或者更改变量

八、单片机实操六:独立按键控制LED灯状态

1、在指定路径下创建工程并添加新文件

2、编写程序

按键消抖,检测松手,才改变LED灯的状态,使其松开按键后长亮或长灭。

#include <STC89C5xRC.H>

void Delay(unsigned int xms)		//@12.000MHz

	unsigned char i, j;
	while(xms)
	
	i = 2;
	j = 239;
	do
	
		while (--j);
	 while (--i);
	xms--;
	



void main()

	while(1)
	
		if(P31==0)
		
			Delay(20);  // Keys away shaking
			while(P31==0);
			Delay(20);  // Detection of let go
			P20=~P20;
		
	

九、单片机实操七:独立按键控制LED显示二进制

1、在指定路径下创建工程并添加新文件

2、编写程序

通过不停的按下按键,使得灯以二进制的方式,不断往上加一,达到用灯来表示按键次数

#include <STC89C5xRC.H>

void Delay(unsigned int xms)		//@12.000MHz

	unsigned char i, j;
	while(xms)
	
	i = 2;
	j = 239;
	do
	
		while (--j);
	 while (--i);
	xms--;
	


void main()

	unsigned char LEDNum=0;  // char max num is 255
	while(1)
	
	if(P31==0)
	
		Delay(20);
		while(P31==0);
		Delay(20);
		LEDNum++;
		P2=~LEDNum;
	
	

十、单片机实操八:独立按键控制LED移位

1、在指定路径下创建工程并添加新文件

2、编写程序

按下P31,往左边移一位;按下P30,往右边移一位,以LED灯来展示。

#include <STC89C5xRC.H>
void Delay(unsigned int xms);  // must statement

unsigned char LEDNum;  // The global variable

void main()

    P2=~0x01; //int P2
	while(1)
	
		if(P31==0)
		
		Delay(20);
		while(P31==0);
		Delay(20);
		LEDNum++;
		if(LEDNum>=8)
			LEDNum=0;
		P2=~(0x01<<LEDNum);  // 0x01 of P2 need shift to the left LEDNum, and get the not
		
		if(P30==0)
		
		Delay(20);
		while(P30==0);
		Delay(20);
		if(LEDNum==0)
			LEDNum=7;
		else
			LEDNum--;
		P2=~(0x01<<LEDNum);
		
	


void Delay(unsigned int xms)		//@12.000MHz

	unsigned char i, j;
	while(xms)
	
	i = 2;
	j = 239;
	do
	
		while (--j);
	 while (--i);
	xms--;
	


十一、单片机实操九:静态数码管显示

1、在指定路径下创建工程并添加新文件

2、单个数码管引脚定义

数码管的接法,有共阳和共阴之分。共阴时,拉高电压即可点亮。共阳时,拉低电平点亮。

 3、开发板四位一体的数码管引脚定义

4、硬件原理图

138译码器控制数码管使能(使用3个单片机输入控制8个数码管显示),每个数字的一个笔画由双向数据缓存器245(单片机输出能力有限,需要该芯片提高输入能力)控制亮灭。

因此,首先控制P22~P24来选中数码管,然后选中数码管的笔画,最终呈现数据。

5、C51单片机数组

 6、C51单片机子函数

 7、数码管段码表(共阴极电路,共阳极则不一样) 

8、编写程序

#include <STC89C5xRC.H>

unsigned char NixieTable[]=

0x3f,0x06,0x5b,0x4f,

0x66,0x6d,0x7d,0x07,

0x7f,0x6f,0x77,0x7c,

0x39,0x5e,0x79,0x71, 0x00;


void Nixie(unsigned char Location,Number)

	switch(Location)
	
		case 1:
			P24=1;P23=1;P22=1;break;
		case 2:
			P24=1;P23=1;P22=0;break;
		case 3:
			P24=1;P23=0;P22=1;break;
		case 4:
			P24=1;P23=0;P22=0;break;
		case 5:
			P24=0;P23=1;P22=1;break;
		case 6:
			P24=0;P23=1;P22=0;break;
		case 7:
			P24=0;P23=0;P22=1;break;
		case 8:
			P24=0;P23=0;P22=0;break;
	
	P0=NixieTable[Number];


void main()

//	P24=1;  //Controls a nixie tube
//	P23=0;
//	P22=1;
//	P0=0x7D;  //value is 6
	Nixie(2,3);
	while(1)
	
		
	

十二、单片机实操十:动态数码管显示

1、在指定路径下创建工程并添加新文件

2、编写程序

动态清零,数字消影,来实现动态数码管显示,这是单片机不断扫描来成像的,将耗费大量CPU资源。因此,硬件电路一般会加1640的芯片来驱动,将大量减少扫描带来的CPU损耗。

#include <STC89C5xRC.H>

unsigned char NixieTable[]=

0x3f,0x06,0x5b,0x4f,

0x66,0x6d,0x7d,0x07,

0x7f,0x6f,0x77,0x7c,

0x39,0x5e,0x79,0x71, 0x00;

void Delay(unsigned int xms)		//@12.000MHz

	unsigned char i, j;
	while(xms)
	
	i = 2;
	j = 239;
	do
	
		while (--j);
	 while (--i);
	xms--;
	


void Nixie(unsigned char Location,Number)

	switch(Location)
	
		case 1:
			P24=1;P23=1;P22=1;break;
		case 2:
			P24=1;P23=1;P22=0;break;
		case 3:
			P24=1;P23=0;P22=1;break;
		case 4:
			P24=1;P23=0;P22=0;break;
		case 5:
			P24=0;P23=1;P22=1;break;
		case 6:
			P24=0;P23=1;P22=0;break;
		case 7:
			P24=0;P23=0;P22=1;break;
		case 8:
			P24=0;P23=0;P22=0;break;
	
	P0=NixieTable[Number];
	Delay(1);  // Shadow elimination
	P0=0x00;  //  reset


void main()

	while(1)
	
		Nixie(1,1);
		Nixie(2,2);
		Nixie(3,3);
	

十三、单片机实操十一:模块化编程

1、在指定路径下创建工程并添加新文件

2、模块化编程

 3、模块化编程框图

4、模块化编程注意事项

 5、C预编译

 6、增加中文注释

7、编写代码

main.c

#include <STC89C5xRC.H>
#include "Delay.h"  // 使用双引号,优先查询工程目录
#include "Nixie.h" 

void main()

	while(1)
	
		Nixie(1,1);
		Nixie(2,2);
		Nixie(3,3);
	

Delay.c

void Delay(unsigned int xms)		//@12.000MHz

	unsigned char i, j;
	while(xms)
	
	i = 2;
	j = 239;
	do
	
		while (--j);
	 while (--i);
	xms--;
	

Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__

void Delay(unsigned int xms);
	
#endif

Nixie.c

#include <STC89C5xRC.H>
#include "Delay.h"

unsigned char NixieTable[]=

0x3f,0x06,0x5b,0x4f,

0x66,0x6d,0x7d,0x07,

0x7f,0x6f,0x77,0x7c,

0x39,0x5e,0x79,0x71, 0x00;


void Nixie(unsigned char Location,Number)

	switch(Location)
	
		case 1:
			P24=1;P23=1;P22=1;break;
		case 2:
			P24=1;P23=1;P22=0;break;
		case 3:
			P24=1;P23=0;P22=1;break;
		case 4:
			P24=1;P23=0;P22=0;break;
		case 5:
			P24=0;P23=1;P22=1;break;
		case 6:
			P24=0;P23=1;P22=0;break;
		case 7:
			P24=0;P23=0;P22=1;break;
		case 8:
			P24=0;P23=0;P22=0;break;
	
	P0=NixieTable[Number];
	Delay(1);  // Shadow elimination
	P0=0x00;  //  reset

Nixie.h

#ifndef __NIXIE_H__
#define __NIXIE_H__

void Nixie(unsigned char Location,Number);
	
#endif

十四、单片机实操十二:LCD1602调试工具

1、在指定路径下创建工程并添加新文件

2、LCD1602调试工具

3、编写程序

main.c

#include <STC89C5xRC.H>
#include "LCD1602.h"

void main()

	LCD_Init();
	LCD_ShowChar(1,1,'B');
	LCD_ShowString(1,3,"Hello");
	LCD_ShowNum(1,9,123,3);
	LCD_ShowSignedNum(1,13,-66,2);
	LCD_ShowHexNum(2,1,0xA8,2);
	LCD_ShowBinNum(2,4,0xAA,8);
	LCD_ShowChar(2,13,'A');
	while(1)
	
	
	

 LCD1602.c

#include <STC89C5xRC.H>


//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()

	unsigned char i, j;

	i = 2;
	j = 239;
	do
	
		while (--j);
	 while (--i);


/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)

	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();


/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)

	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();


/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)

	if(Line==1)
	
		LCD_WriteCommand(0x80|(Column-1));
	
	else if(Line==2)
	
		LCD_WriteCommand(0x80|(Column-1+0x40));
	


/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()

	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏


/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)

	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);


/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)

	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\\0';i++)
	
		LCD_WriteData(String[i]);
	


/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)

	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	
		Result*=X;
	
	return Result;


/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)

	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	


/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)

	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	
		LCD_WriteData('+');
		Number1=Number;
	
	else
	
		LCD_WriteData('-');
		Number1=-Number;
	
	for(i=Length;i>0;i--)
	
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	


/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)

	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		
			LCD_WriteData(SingleNumber+'0');
		
		else
		
			LCD_WriteData(SingleNumber-10+'A');
		
	


/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)

	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	

 LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

4、注意事项

单引号和双引号都有全角和半角之分,全角的又叫中文字符,半角的又称英文字符。在c语言中,全角字符没有任何意义,它就是一个普通字符,没有含义;半角字符才有不同的意义:
        双引号用来括起一个字符串,如"China";
        单引号原来括起一个字符,如'f'。
二者含义不同,不能混用。

十五、单片机实操十三:矩阵键盘

1、在指定路径下创建工程并添加新文件

2、矩阵键盘介绍

3、扫描的概念

4、硬件连线

我们想选取1、5、9、13,即第一列,可以先把P1全部置为高,即全部拉高;接着让P13拉低,则选中了第一列。其他也这样操作。

 5、编写程序

main.c

#include <STC89C5xRC.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey.h"

unsigned char KeyNum;

void main()

	LCD_Init();
//	LCD_ShowChar(1,1,'B');
	LCD_ShowString(1,3,"MatrixKey:");
//	LCD_ShowNum(1,9,123,3);
//	LCD_ShowSignedNum(1,13,-66,2);
//	LCD_ShowHexNum(2,1,0xA8,2);
//	LCD_ShowBinNum(2,4,0xAA,8);
//	LCD_ShowChar(2,13,'A');
	while(1)
	
		KeyNum=MatrixKey();
		if(KeyNum)
		
			LCD_ShowNum(2,3,KeyNum,2);
		
	

MatrixKey.c

#include <STC89C5xRC.H>
#include "Delay.h"

unsigned char MatrixKey()

	unsigned char KeyNumber=0;
	
	P1=0xFF;
	P13=0;
	if(P17==0)Delay(20);while(P17==0);Delay(20);KeyNumber=1;
	if(P16==0)Delay(20);while(P16==0);Delay(20);KeyNumber=5;
	if(P15==0)Delay(20);while(P15==0);Delay(20);KeyNumber=9;
	if(P14==0)Delay(20);while(P14==0);Delay(20);KeyNumber=13;
	
	P1=0xFF;
	P12=0;
	if(P17==0)Delay(20);while(P17==0);Delay(20);KeyNumber=2;
	if(P16==0)Delay(20);while(P16==0);Delay(20);KeyNumber=6;
	if(P15==0)Delay(20);while(P15==0);Delay(20);KeyNumber=10;
	if(P14==0)Delay(20);while(P14==0);Delay(20);KeyNumber=14;
	
	P1=0xFF;
	P11=0;
	if(P17==0)Delay(20);while(P17==0);Delay(20);KeyNumber=3;
	if(P16==0)Delay(20);while(P16==0);Delay(20);KeyNumber=7;
	if(P15==0)Delay(20);while(P15==0);Delay(20);KeyNumber=11;
	if(P14==0)Delay(20);while(P14==0);Delay(20);KeyNumber=15;
	
	P1=0xFF;
	P10=0;
	if(P17==0)Delay(20);while(P17==0);Delay(20);KeyNumber=4;
	if(P16==0)Delay(20);while(P16==0);Delay(20);KeyNumber=8;
	if(P15==0)Delay(20);while(P15==0);Delay(20);KeyNumber=12;
	if(P14==0)Delay(20);while(P14==0);Delay(20);KeyNumber=16;
	
	return KeyNumber;

MatrixKey.h

#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__

unsigned char MatrixKey();
	
#endif

其它文件:复制之前写的模块即可。

6、软件使用技巧:配置模板

 

 

十六、单片机实操十四:矩阵键盘密码锁

1、复制工程后打开

2、编写程序

main.c

#include <STC89C5xRC.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey.h"

unsigned char KeyNum;
unsigned int Password, Count;

void main()

	LCD_Init();
//	LCD_ShowChar(1,1,'B');
	LCD_ShowString(1,1,"Password:");
//	LCD_ShowNum(1,9,123,3);
//	LCD_ShowSignedNum(1,13,-66,2);
//	LCD_ShowHexNum(2,1,0xA8,2);
//	LCD_ShowBinNum(2,4,0xAA,8);
//	LCD_ShowChar(2,13,'A');
	while(1)
	
		KeyNum=MatrixKey();
		if(KeyNum)
		
			if(KeyNum<=10)  // 如果S1~S10按键按下,输入密码
			
				if(Count<4)  // 密码四位数
				
				Password*=10;  //  密码左移一位,这样就可以依次输入密码
				Password+=KeyNum%10;  // 获取一位密码,加入到原密码,此时10为0
				Count++;
				
			
			LCD_ShowNum(2,1,Password,4);
			if(KeyNum==11)  // 确认
			
				if(Password==1234)
				
					LCD_ShowString(1,14,"OK ");
					Password=0;
					Count=0;
					LCD_ShowNum(2,1,Password,4);
				
				else
				
					LCD_ShowString(1,14,"ERR");
					Password=0;
					Count=0;
					LCD_ShowNum(2,1,Password,4);
				
			
			if(KeyNum==12)  //取消
			
					Password=0;
					Count=0;
					LCD_ShowString(1,14,"   ");
					LCD_ShowNum(2,1,Password,4);
			
		
	

其它文件:复制之前写的模块即可。

十七、单片机实操十五:定时器与按键控制LED流水灯模式

1、定时器介绍

2、STC89C52定时器资源

3、定时器狂框图 

 4、定时器工作模式

 5、中断系统

 6、中断程序流程

 7、STC89C52中断资源

 8、定时器和中断系统

 9、定时器相关寄存器

10、编写程序

通过独立按键控制流水灯模式,并由定时器执行流水灯。

main.c

#include <STC89C5xRC.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>

unsigned char KeyNum,LEDMode;

void main()

	P2=0xFE;
	Timer0Init();
	while(1)
	
		KeyNum=Key();		//获取独立按键键码
		if(KeyNum)			//如果按键按下
		
			if(KeyNum==1)	//如果K1按键按下
			
				LEDMode++;	//模式切换,按1下按键是模式1,按2下是模式0,默认模式0
				if(LEDMode>=2)LEDMode=0;
			
		
	


void Timer0_Routine() interrupt 1  //中断函数标识,含优先级

	static unsigned int T0Count;  //静态变量,拥有局部作用域,全局生命周期
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;		//T0Count计次,对中断频率进行分频
	if(T0Count>=500)//分频500次,500ms
	
		T0Count=0;
		if(LEDMode==0)			//模式判断
			P2=_crol_(P2,1);	//LED输出(循环左移函数,即使流水灯循环左移)
		if(LEDMode==1)
			P2=_cror_(P2,1);
	

Timer0.c

#include <STC89C5xRC.H>


/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)

	TMOD &= 0xF0;		//设置定时器模式,只改变T0,避免T1改变
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//高位设置定时初值 65535/256
	TH0 = 0xFC;		//低位设置定时初值 65535%256
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;


/*定时器中断函数模板
void Timer0_Routine() interrupt 1

	static unsigned int T0Count;  //静态变量,拥有局部作用域,全局生命周期
	TL0 = 0x18;		//设置定时初值,像沙漏,重置沙漏时间
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	
		T0Count=0;
		
	

*/

Timer0.h

#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0Init(void);

#endif

Key.c

#include <STC89C5xRC.H>
#include "Delay.h"

/**
  * @brief  获取独立按键键码
  * @param  无
  * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0
  */
unsigned char Key()

	unsigned char KeyNumber=0;
	
	if(P31==0)Delay(20);while(P31==0);Delay(20);KeyNumber=1;
	if(P30==0)Delay(20);while(P30==0);Delay(20);KeyNumber=2;
	if(P32==0)Delay(20);while(P32==0);Delay(20);KeyNumber=3;
	if(P33==0)Delay(20);while(P33==0);Delay(20);KeyNumber=4;
	
	return KeyNumber;

Key.h

#ifndef __KEY_H__
#define __KEY_H__

unsigned char Key();

#endif

其它文件:复制之前写的模块即可。

11、定时器代码获取

十八、单片机实操十六:定时器时钟

1、编写程序

制作一个一天时间的计时器。

main.c

#include <STC89C5xRC.H>
#include "Timer0.h"
#include "Delay.h"
#include "LCD1602.h"

unsigned char Sec, Min=59, Hour=23;

void main()

	Timer0Init();
	LCD_Init();
	LCD_ShowString(1,1,"Clock:");
	while(1)
	
		LCD_ShowNum(2,1,Hour,2);
		LCD_ShowString(2,3,":");
		LCD_ShowNum(2,4,Min,2);
		LCD_ShowString(2,6,":");
		LCD_ShowNum(2,7,Sec,2);
	


void Timer0_Routine() interrupt 1  //中断函数标识,含优先级

	static unsigned int T0Count;  //静态变量,拥有局部作用域,全局生命周期
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;		//T0Count计次,对中断频率进行分频
	if(T0Count>=1000)//1000ms
	
		T0Count=0;
		Sec++;
		if(Sec>=60)
		
			Sec=0;
			Min++;
			if(Min>=60)
			
				Min=0;
				Hour++;
				if(Hour>=24)
				
					Hour=0;
				
			
		
	

其它文件:复制之前写的模块即可。

十九、单片机实操十七:串口通信与串口向电脑发送数据

1、串口介绍

2、接口及引脚定义

 3、硬件电路

 4、电平标准

 5、常见通信接口比较

 6、相关术语

 7、51单片机的UART

 8、串口参数与时序图

 9、串口模式图

 10、串口相关寄存器

 11、串口和中断系统

11、使用工具生成串口配置

 12、编写程序

main.c

#include <STC89C5xRC.H>
#include "Delay.h"
#include "UART.h"

unsigned char Sec;

void main()

	UartInit();
	while(1)
	
		UART_SendByte(Sec);
		Sec++;
		Delay(1);  // 必要的延时,避免误差导致乱码,没误差的时候可以不需要
	

UART.c

#include <STC89C5xRC.H>

void UartInit(void)		//4800bps@11.0592MHz

	PCON &= 0x80;		//波特率不倍速
	SCON = 0x40;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFA;		//设置定时初始值
	TH1 = 0xFA;		//设置定时重载值
	ET1 = 0;		//禁止定时器%d中断
	TR1 = 1;		//定时器1开始计时


void UART_SendByte(unsigned char Byte)

	SBUF=Byte;  // 根据硬件原理,操作寄存器
	while(TI==0);  // 操作寄存器,检测是否完成
	TI=0;  // 按要求重新赋值为0

UART.h

#ifndef __UART_H__
#define __UART_H__

void UartInit(void);
void UART_SendByte(unsigned char Byte);

#endif

其他文件:复制之前写的模块即可。

13、调试程序

二十、单片机实操十八:电脑通过串口控制LED

1、编写程序

#include <STC89C5xRC.H>
#include "Delay.h"
#include "UART.h"

unsigned char Sec;

void main()

	UartInit();
	while(1)
	

	


void UART_Routine() interrupt 4

	if(RI==1)
	
		P2=~SBUF;  // 读寄存器的数据
		UART_SendByte(SBUF);
		RI=0;  // 说明书要求手动复位
	

其他文件:复制之前写的模块即可。

2、波特率计算

(1)内部逻辑图

(2)配置的定时初值

 (3)计算方式

 F3=243;

256-243=13us;

每记13次数,溢出1次;

1/13=0.0769230769230769MHz;

0.0769230769230769/16=0.0048076923076923MHz=4,807.692307692308HZ

3、ASCII码编码表

文本模式与Hex模式对应情况。

二十一、单片机实操十九:LED点阵屏与显示图形

1、LED点阵屏介绍

 2、显示原理

 3、74HC595模块原理图

4、74HC595介绍

 5、接线

OE要通过跳线帽与GND相连,而开发板默认OE与VCC相连,因此需要操作。

6、开发板引脚对应关系

7、C51的sfr、sbit 

8、编写程序

main.c

#include <STC89C5xRC.H>
#include "Delay.H"

sbit RCK=P3^5;  //RCLK
sbit SCK=P3^6;  //SRCLK
sbit SER=P3^4;	//SER

#define MATRIX_LED_PORT  P0

void _74HC595_WriteByte(unsigned char Byte)

//	SER=Byte&0x80;  //一般是0、1赋值,不过,如果非0,都会当作1
//	SCK=1;
//	SCK=0;
//	SER=Byte&0x60;
//	SCK=1;
//	SCK=0;
	unsigned char i;
	for(i=0;i<8;i++)
	
		SER=Byte&(0x80>>i);
		SCK=1;
		SCK=0;
	
		RCK=1;
		RCK=0;


void MatrixLED_ShowColumn(unsigned char Column, Data)

	_74HC595_WriteByte(Data);
//	if(Column==0)P0=~0x80;
//	if(Column==1)P0=~0x40;
	MATRIX_LED_PORT=~(0x80>>Column);
	Delay(1);
	MATRIX_LED_PORT=0xFF;
	


void main()

	SCK=0;
	RCK=0;
	while(1)
	
//		_74HC595_WriteByte(0xAA);
		MatrixLED_ShowColumn(0,0x80);
		MatrixLED_ShowColumn(1,0x40);
		MatrixLED_ShowColumn(2,0x20);
		MatrixLED_ShowColumn(3,0x10);
	

二十二、单片机实操二十:LED点阵屏显示动画

1、字模提取软件

 

 

 

 

 取出数据如下,将作为程序数组使用:

0xFF,0x10,0x10,0x10,0xFF,0x00,0x1E,0x29,0x29,0x29,0x18,0x00,0xFE,0x01,0x02,0x00,
0xFE,0x01,0x02,0x00,0x0E,0x11,0x11,0x0E,0x00,0x7D,0x7D,0x00,0x00,0x00,0x00,0x00,

2、编写程序

main.c

#include <STC89C5xRC.H>
#include "Delay.H"
#include "MatrixLED.H"

unsigned char Animation[]=
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 为了显示更好看,避免第一列直接显示字符本身
0xFF,0x10,0x10,0x10,0xFF,0x00,0x1E,0x29,0x29,0x29,0x18,0x00,0xFE,0x01,0x02,0x00,
0xFE,0x01,0x02,0x00,0x0E,0x11,0x11,0x0E,0x00,0x7D,0x7D,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  // 为了显示更好看
;

void main()

	unsigned char i, Offset=1, Count=0;
	while(1)
	
	for(i=0;i<8;i++)
		
			MatrixLED_ShowColumn(i,Animation[i+Offset]);
		
		Count++;
		if(Count>10)
		
			Count=0;
			Offset++;
			if(Offset>40)
			
			Offset=0; //防止数组溢出
			
		
	

MatrixLED.c

#include <STC89C5xRC.H>
#include "Delay.H"

sbit RCK=P3^5;  //RCLK
sbit SCK=P3^6;  //SRCLK
sbit SER=P3^4;	//SER

#define MATRIX_LED_PORT  P0

void _74HC595_WriteByte(unsigned char Byte)

//	SER=Byte&0x80;  //一般是0、1赋值,不过,如果非0,都会当作1
//	SCK=1;
//	SCK=0;
//	SER=Byte&0x60;
//	SCK=1;
//	SCK=0;
	unsigned char i;
	for(i=0;i<8;i++)
	
		SER=Byte&(0x80>>i);
		SCK=1;
		SCK=0;
	
		RCK=1;
		RCK=0;


void MatrixLED_Init()

	SCK=0;
	RCK=0;



void MatrixLED_ShowColumn(unsigned char Column, Data)

	_74HC595_WriteByte(Data);
//	if(Column==0)P0=~0x80;
//	if(Column==1)P0=~0x40;
	MATRIX_LED_PORT=~(0x80>>Column);
	Delay(1);
	MATRIX_LED_PORT=0xFF;
	

MatrixLED.h

#ifndef __MATRIXLED_H__
#define __MATRIXLED_H__

void MatrixLED_ShowColumn(unsigned char Column, Data);
void MatrixLED_Init();

#endif

3、注意事项

将数据放在flash里面,用来避免内存被消耗过多,但这种数据是不能更改的,方法如下:

unsigned char Animation[]

改为

unsigned char code Animation[]

二十三、单片机实操二十一:DS1302实时时钟

1、DS1302介绍

2、引脚定义和应用电路

3、内部结构图

4、寄存器定义

 5、时序定义

 6、BCD码

7、编写代码

main.c

#include <STC89C5xRC.H>
#include "LCD1602.h"
#include "DS1302.h"

//  unsigned char Second, Minute;

void main()

	LCD_Init();
	DS1302_Init();
	
//	DS1302_WriteByte(0x8E, 0x00);  // 解除芯片写保护,避免数值不动
//	DS1302_WriteByte(0x80, 0x54);
	
	DS1302_SetTime();
	
	while(1)
	
		DS1302_ReadTime();
		LCD_ShowNum(1,1,DS1302_TIME[0],2);
		LCD_ShowNum(1,4,DS1302_TIME[1],2);
		LCD_ShowNum(1,7,DS1302_TIME[2],2);
		LCD_ShowNum(2,1,DS1302_TIME[3],2);
		LCD_ShowNum(2,4,DS1302_TIME[4],2);
		LCD_ShowNum(2,7,DS1302_TIME[5],2);

//		Second=DS1302_ReadByte(0x81);
//		Minute=DS1302_ReadByte(0x83);
//		LCD_ShowNum(2,1,Second/16*10+Second%16,2);
//		LCD_ShowNum(2,3,Minute/16*10+Minute%16,2);
	

DS1302.c

#include <STC89C5xRC.H>

sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;

#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8E


unsigned char DS1302_TIME[]=19,11,16,12,59,55,6;

void DS1302_Init(void)

	DS1302_CE=0;
	DS1302_SCLK=0;


void DS1302_WriteByte(unsigned char Command, Data)

	unsigned char i;
	DS1302_CE=1;
	
//	DS1302_IO=Command&0x01;
//	DS1302_SCLK=1;  // 速度慢可以不加延时,有些速度快的芯片需要增加延时
//	DS1302_SCLK=0;
//	
//	DS1302_IO=Command&0x02;
//	DS1302_SCLK=1;
//	DS1302_SCLK=0;
	for(i=0;i<8;i++)
	
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	
	for(i=0;i<8;i++)
	
		DS1302_IO=Data&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	
	DS1302_CE=0; //完成一次操作,释放IO


unsigned char DS1302_ReadByte(unsigned char Command)

	unsigned char i,Data=0x00;
	Command|=0x01;  //
	DS1302_CE=1;
	for(i=0;i<8;i++)
	
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=0;  //根据时序操作
		DS1302_SCLK=1;
	
//	DS1302_SCLK=0;
//	DS1302_SCLK=1;
//	if(DS1302_IO)
//	
//		Data=Data|0x01;
//	
//	DS1302_SCLK=0;
//	DS1302_SCLK=1;
//	if(DS1302_IO)
//	
//		Data=Data|0x02;
//	
		for(i=0;i<8;i++)
	
		DS1302_SCLK=1;  //重复置1是去掉一个周期,为的是满足时序
		DS1302_SCLK=0;
		if(DS1302_IO)Data|=(0x01<<i);
	
	DS1302_CE=0;
	DS1302_IO=0;  // 如果不加这一行,将显示全0
	return Data;


void DS1302_SetTime(void)

	DS1302_WriteByte(DS1302_WP,0x00);
	DS1302_WriteByte(DS1302_YEAR,DS1302_TIME[0]/10*16+DS1302_TIME[0]%10);
	DS1302_WriteByte(DS1302_MONTH,DS1302_TIME[1]/10*16+DS1302_TIME[1]%10);
	DS1302_WriteByte(DS1302_DATE,DS1302_TIME[2]/10*16+DS1302_TIME[2]%10);
	DS1302_WriteByte(DS1302_HOUR,DS1302_TIME[3]/10*16+DS1302_TIME[3]%10);
	DS1302_WriteByte(DS1302_MINUTE,DS1302_TIME[4]/10*16+DS1302_TIME[4]%10);
	DS1302_WriteByte(DS1302_SECOND,DS1302_TIME[5]/10*16+DS1302_TIME[5]%10);
	DS1302_WriteByte(DS1302_DAY,DS1302_TIME[6]/10*16+DS1302_TIME[6]%10);
	DS1302_WriteByte(DS1302_WP,0x00);


void DS1302_ReadTime(void)

	unsigned char Temp;
	Temp=DS1302_ReadByte(DS1302_YEAR);
	DS1302_TIME[0]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_MONTH);
	DS1302_TIME[1]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DATE);
	DS1302_TIME[2]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_HOUR);
	DS1302_TIME[3]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_MINUTE);
	DS1302_TIME[4]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_SECOND);
	DS1302_TIME[5]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DAY);
	DS1302_TIME[6]=Temp/16*10+Temp%16;

DS1302.h

#ifndef __DS1302_H__
#define __DS1302_H__

extern unsigned char DS1302_TIME[];  // 声明数组

void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command, Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);

#endif

二十四、单片机实操二十二:DS1302可调时钟

1、编写程序

main.c

#include <STC89C5xRC.H>
#include "LCD1602.h"
#include "DS1302.h"
#include "Key.h"
#include "Timer0.h"

unsigned char KeyNum,MODE,TimeSetSelect,TimeSetFlashFlag;

void TimeShow(void)//时

以上是关于C语言:51单片机看这一篇就够了的主要内容,如果未能解决你的问题,请参考以下文章

初识Redis,看这一篇就够了

[建议速看] 学习Python的小白了解 Python看这一篇就够了!

[建议速看] 学习Python的小白了解 Python看这一篇就够了!

菜鸟用Python操作MongoDB,看这一篇就够了

JSON入门看这一篇就够了

Perl 语言输入输出怎么写?控制结构如何用?看这一篇就够了!