单片机STC89C51入门学习笔记--基础实验例程(一)

文章目录

  • 前言
  • 1. 点亮第一个LED
    • 1.1 代码
    • 1.2 编译
    • 1.3 程序下载
    • 1.4 结果展示
    • 1.5 常见问题及解决办法
  • 2. LED灯闪烁
    • 2.1 代码
    • 2.2 编译
    • 2.3 程序下载
    • 2.4 结果展示
    • 2.5 常见问题及解决办法
  • 3. LED流水灯
    • 3.1 代码
    • 3.2 编译
    • 3.3 程序下载
    • 3.4 结果展示
    • 3.5 常见问题及解决办法
  • 4. 蜂鸣器
    • 4.1 代码
    • 4.2 编译
    • 4.3 程序下载
    • 4.4 结果展示
    • 4.5 常见问题及解决办法
  • 5. 动态数码管显示
    • 5.1 代码
    • 5.2 编译
    • 5.3 程序下载
    • 5.4 结果展示
    • 5.5 常见问题及解决办法
  • 6. 独立按键
    • 6.1 代码
    • 6.2 编译
    • 6.3 程序下载
    • 6.4 结果展示
    • 6.5 常见问题及解决办法
  • 7. 矩阵按键
    • 7.1 代码
    • 7.2 编译
    • 7.3 程序下载
    • 7.4 结果展示
    • 7.5 常见问题及解决办法
  • 8. 单片机IO扩展--74HC595
    • 8.1 代码
    • 8.2 编译
    • 8.3 程序下载
    • 8.4 结果展示
    • 8.5 常见问题及解决办法
  • 9. LED点阵(点亮一个点)
    • 9.1 代码
    • 9.2 编译
    • 9.3 程序下载
    • 9.4 结果展示
    • 9.5 常见问题及解决办法
  • 10. LED点阵(显示数字)
    • 10.1 代码
    • 10.2 编译
    • 10.3 程序下载
    • 10.4 结果展示
    • 10.5 常见问题及解决办法
  • 11. 直流电机
    • 11.1 代码
    • 11.2 编译
    • 11.3 程序下载
    • 11.4 结果展示
    • 11.5 常见问题及解决办法
  • 12. 外部中断0
    • 12.1 代码
    • 12.2 编译
    • 12.3 程序下载
    • 12.4 结果展示
    • 12.5 常见问题及解决办法
  • 13. 定时器0中断
    • 13.1 代码
    • 13.2 编译
    • 13.3 程序下载
    • 13.4 结果展示
    • 13.5 常见问题及解决办法
  • 14. 串口通信
    • 14.1 代码
    • 14.2 编译
    • 14.3 程序下载
    • 14.4 结果展示
    • 14.5 常见问题及解决办法
  • 15. EEPROM-IIC
    • 15.1 代码
    • 15.2 编译
    • 15.3 程序下载
    • 15.4 结果展示
    • 15.5 常见问题及解决办法
  • 16. DS18B20温度传感器
    • 16.1 代码
    • 16.2 编译
    • 16.3 程序下载
    • 16.4 结果展示
    • 16.5 常见问题及解决办法
  • 17. DS1302时钟
    • 17.1 代码
    • 17.2 编译
    • 17.3 程序下载
    • 17.4 结果展示
    • 17.5 常见问题及解决办法
  • 18. AD模数转换
    • 18.1 代码
    • 18.2 编译
    • 18.3 程序下载
    • 18.4 结果展示
    • 18.5 常见问题及解决办法
  • 19. DA数模转换
    • 19.1 代码
    • 19.2 编译
    • 19.3 程序下载
    • 19.4 结果展示
    • 19.5 常见问题及解决办法
  • 20. LCD1602液晶
    • 20.1 代码
    • 20.2 编译
    • 20.3 程序下载
    • 20.4 结果展示
    • 20.5 常见问题及解决办法

前言

本笔记用于记录STC89C51单片机开发板入门学习,此部分为基础实验例程。开始实验前建议学习《10天学会51单片机-郭天祥》,另外还需要一定的C语言基础。
准备环境:

  1. 笔记本一台;
  2. STC89C51开发板一套(我选用的是普中51-单核-A2开发板,入手价格56元,因为便宜买的);
  3. 串口助手软件STC-ISP(用于程序下,也可用商家自带的程序下载软件);
  4. KeiluVision5软件(用于程序开发,安装和教程自行百度)。

1. 点亮第一个LED

本条所要实现的功能是:点亮D1发光二极管,即让P2.0管脚输出一个低电平。

1.1 代码

/*********************
点亮第一个LED灯实验
实验现象:下载程序后D1指示灯点亮
日期:2020-04-11
作者:lixs
**********************/
#include 

sbit led=P2^0;//将单片机P2.0端口定义为led

void main()
{
		led=0;//p2.0端口设置为低电平
		while(1);//循环语句
		
}

1.2 编译

编译前需要在KeiluVision5软件进行设置:1)options选项;2)output选项;3)勾选create HEX file;4)命名Name of Executable。如下图所示:
单片机STC89C51入门学习笔记--基础实验例程(一)_第1张图片
设置完成后进行编译。如下图所示:
单片机STC89C51入门学习笔记--基础实验例程(一)_第2张图片
编译完成后会生成.hex文件。如下图所示:
单片机STC89C51入门学习笔记--基础实验例程(一)_第3张图片
至此编译工作完成。

1.3 程序下载

编译生成.hex文件后,打开STC-ISP软件,将此.hex文件下载到单片机中。

STC-ISP软件设置。如下图所示:
单片机STC89C51入门学习笔记--基础实验例程(一)_第4张图片
软件设置完成后,开始下载程序:1)点击打开程序文件;2)选择.hex文件;3)点击下载/编程。如下图所示:
单片机STC89C51入门学习笔记--基础实验例程(一)_第5张图片
点击下载程序后会出现:正在检测目标单片机…,此时检查单片机是否上电。如已上电,请关闭电源,重新上电,即可完成程序下载。如下图所示:
单片机STC89C51入门学习笔记--基础实验例程(一)_第6张图片
单片机正常连接后,会完成程序下载,STC-ISP软件会提示程序下载结果。如下图所示:
单片机STC89C51入门学习笔记--基础实验例程(一)_第7张图片

1.4 结果展示

单片机STC89C51入门学习笔记--基础实验例程(一)_第8张图片

1.5 常见问题及解决办法

2. LED灯闪烁

本条所要实现的功能是:让D1发光二极管固定周期闪烁,即让P2.0管脚先输出一个低电平点亮D1,然后固定周期后输出一个高电平熄灭D1。这就需要增加一个延时,我们利用c语言中的循环函数,让CPU不断循环执行即可实现延时功能。

2.1 代码

/*********************
LED灯闪烁实验
实验现象:下载程序后D1指示灯闪烁
日期:2020-04-11
作者:lixs
**********************/
#include 
typedef unsigned int uint16;
sbit led=P2^0;//将单片机P2.0端口定义为led
void delay(uint16 x);

void main()
{
		while(1)
		{
				led=0;//p2.1端口设置为低电平,即点亮D1
				delay(50000);//循环50000次,即大约延时500ms
				led=1;//p2.1端口设置为高电平,即熄灭D1
				delay(50000);//循环50000次,即大约延时500ms
		}
}

void delay(uint16 x)//延时函数,当x=1时,大约延时10us
{
		while(x--);
}

2.2 编译

编译过程同1.2一致。

2.3 程序下载

程序下载过程同1.3一致。

2.4 结果展示

2.5 常见问题及解决办法

问题1:为什么如果将延时函数中的形参x赋值超过65535即LED灯延时间隔即呈现非正常状态?
解决办法:因为x数据类型为unsigned int类型,最大值为65535,因此x会溢出,导致非正常状态出现,x的赋值一定要严格在数据类型的取值范围内,否则不会得到预期结果。

3. LED流水灯

3.1 代码

/*********************
LED流水灯实验
实验现象:下载程序后D1-D8指示灯循环逐个点亮
日期:2020-04-11
作者:lixs
**********************/
#include 
#include         //左右移函数头文件
#define led P2              //定义P2端口为led,即可用led代替P2端口
typedef unsigned int uint16;//对数据类型进行声明定义
typedef unsigned char uchar8;//对数据类型进行声明定义
uchar8 i;//初始化变量i
void delay(uint16);//声明延时函数


//主函数:实现led灯流水效果(采用<<左移运算符实现)
/*void main()
{
		led=~0x01;
		delay(50000);
		while(1)
		{
			for(i=0;i<8;i++)
			{
					led=~(0x01<

//主函数:实现led灯流水效果(采用左移函数实现)
void main()
{
		led=~0x01;//0x01取反即为0xFE,也可直接写led=0xFE
		delay(50000);//循环50000次,即大约延时500ms
		while(1)
		{
			for(i=0;i<8;i++)//循环8次,即与D1-D8一一对应
			{
					led=_crol_(led,1);//左移函数,将led的值左移1位,然后将结果赋值到led中
					delay(50000);//循环50000次,即大约延时500ms
			}
		}
}

//延时函数,x=1时,大约延时10us
void delay(uint16 x)
{
		while(x--);
}

3.2 编译

编译过程同1.2一致。

3.3 程序下载

程序下载过程同1.3一致。

3.4 结果展示

3.5 常见问题及解决办法

问题1: 为什么LED流水灯点亮的同时,数码管也会跟着流动点亮?
解决办法:经查看开发板原理图得知,此现象是由于硬件电路导致,非程序影响。


由于工作原因,无法保证定期更新实验例程,还请谅解。以下实验例程会不定期更新,欢迎随时光临指导。

4. 蜂鸣器

4.1 代码

/*********************
蜂鸣器发声实验
实验现象:下载程序后蜂鸣器模块发声
日期:2020-04-11
作者:lixs
**********************/

#include 
sbit buzzer=P1^5;//将单片机P1.5端口定义为buzzer
typedef unsigned int uint16;//对数据类型进行声明定义
void delay(uint16 x);//声明延时函数

void main()
{
		while(1)
		{
			//通过给P1.5端口赋值方式使蜂鸣器发生
			/*buzzer=0;//将P1.5端口置0,即蜂鸣器端输入低电平
			delay(1000);
			buzzer=1;//将P1.5端口置1,即蜂鸣器端输入高电平
			delay(1000);*/
			
			//通过取反方式使蜂鸣器发生
			buzzer=~buzzer;//buzzer刚开始是0x01,然后循环取反,即可达到0/1切换的效果
			delay(100);//循环100次,即大约延时1ms
		}
		
}

void delay(uint16 x)//延时函数,当x=1时,大约延时10us
{
		while(x--);
}

4.2 编译

编译过程同1.2一致。

4.3 程序下载

程序下载过程同1.3一致。

4.4 结果展示

  • 待上传视频

4.5 常见问题及解决办法

5. 动态数码管显示

5.1 代码

/*********************
动态数码管实验
实验现象:下载程序后动态数码管依次显示数字0-7
日期:2020-04-13
作者:lixs
**********************/

#include 
sbit LSA=P2^2;//将单片机P2.2端口定义为LSA
sbit LSB=P2^3;//将单片机P2.3端口定义为LSB
sbit LSC=P2^4;//将单片机P2.4端口定义为LSC
typedef unsigned int uint16;//对数据类型进行声明定义
typedef unsigned char uchar8;//对数据类型进行声明定义
uchar8 code duanxuan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//段选显示0-F的值
void delay(uint16);//声明延时函数
void DigDisplay();//声明数码管显示函数
													
void main()
{
	//发送位选
	while(1)
	{
		DigDisplay();		
	}			
}

void DigDisplay()//位选、段选函数,即选择点亮第几个数码管,并显示数字几
{
	uchar8 i;
	for(i=0;i<8;i++)
	{
		switch(i)
		{
			case(0):LSA=1;LSB=1;LSC=1;break;//显示第0位,即点亮LED8,左1
			case(1):LSA=0;LSB=1;LSC=1;break;//显示第1位,即点亮LED7,左2
			case(2):LSA=1;LSB=0;LSC=1;break;//显示第2位,即点亮LED6,左3
			case(3):LSA=0;LSB=0;LSC=1;break;//显示第3位,即点亮LED5,左4
			case(4):LSA=1;LSB=1;LSC=0;break;//显示第4位,即点亮LED4,左5
			case(5):LSA=0;LSB=1;LSC=0;break;//显示第5位,即点亮LED3,左6
			case(6):LSA=1;LSB=0;LSC=0;break;//显示第6位,即点亮LED2,左7
			case(7):LSA=0;LSB=0;LSC=0;break;//显示第7位,即点亮LED1,左8	
		}
		P0=duanxuan[i];//发送段选,即选择显示数字几
		delay(100);//延时函数,大约延时1ms
		P0=0x00;//消隐
	}
}

void delay(uint16 x)//延时函数,x=1时大约延时10us
{
	while(x--); 
}


5.2 编译

编译过程同1.2一致。

5.3 程序下载

程序下载过程同1.3一致。

5.4 结果展示

  • 待上传视频

5.5 常见问题及解决办法

6. 独立按键

6.1 代码

/*********************
独立按键实验
实验现象:下载程序后按下K1按键可以对D1灯状态取反
日期:2020-04-13
作者:lixs
**********************/

#include 
sbit led=P2^0;//将单片机P2.0端口定义为led
sbit k1=P3^1;//将单片机P3.1端口定义为k1
typedef unsigned int uint16;//对数据类型进行声明定义
typedef unsigned char uchar8;//对数据类型进行声明定义
void delay(uint16);//声明延时函数
void keypros();
													
void main()
{
	led=1;					
	while(1)
	{
		keypros();	
	}			
}

void keypros()			//按键处理函数
{
	if(k1==0)				//检测按键是否按下
	{
		delay(1000);//延时10ms,消除抖动
		if(k1==0)
		{
			led=~led;//led状态取反
		}
		while(!k1);	/*!k1 = !k1==1 = k1==0 检测按键是否松开,
								如k1=0则表示还没松开,保持在当前循环,
								k1=1则表示松开,跳出当前循环等待下次状态变化*/
	}
	
}

void delay(uint16 x)//延时函数,x=1时大约延时10us
{
	while(x--); 
}


6.2 编译

编译过程同1.2一致。

6.3 程序下载

程序下载过程同1.3一致。

6.4 结果展示

  • 待上传视频

6.5 常见问题及解决办法

7. 矩阵按键

7.1 代码

/*********************
矩阵按键实验
实验现象:下载程序后数码管显示0,按下矩阵按键上的按键显示对应的数字
日期:2020-04-13
作者:lixs
**********************/

#include 
#define GPIO_DIG P0//将单片机P0端口定义为GPIO_DIG,即可用GPIO_DIG代替P0
#define GPIO_KEY P1//将单片机P1端口定义为GPIO_KEY,即可用GPIO_DIG代替P1

typedef unsigned int uint16;//对数据类型进行声明定义
typedef unsigned char uchar8;//对数据类型进行声明定义
uchar8 code duanxuan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//段选显示0-F的值
uchar8 KeyValue;
void delay(uint16);//声明延时函数
void KeyDown();
													
void main()
{
		while(1)
		{
			KeyDown();
			GPIO_DIG=duanxuan[KeyValue];
		}			
}

void KeyDown()
{
	char a=0;
	GPIO_KEY=0x0f;
	if(GPIO_KEY!=0x0f)
	{
		delay(1000);
		if(GPIO_KEY != 0x0f)
		{
			GPIO_KEY=0x0f;  
			switch(GPIO_KEY)
			{
				case(0x07):KeyValue=0;break;
				case(0x0b):KeyValue=1;break;
				case(0x0d):KeyValue=2;break;
				case(0x0e):KeyValue=3;break;
			}
			GPIO_KEY=0xf0;
			switch(GPIO_KEY)
			{
				case(0x70):KeyValue=KeyValue;break;
				case(0xb0):KeyValue=KeyValue+4;break;
				case(0xd0):KeyValue=KeyValue+8;break;
				case(0xe0):KeyValue=KeyValue+12;break;
			}
		}
	}
	while((a<50)&&(GPIO_KEY != 0xf0))
	{
		delay(100);
		a++;
	}
}

void delay(uint16 x)//延时函数,x=1时大约延时10us
{
	while(x--); 
}


7.2 编译

编译过程同1.2一致。

7.3 程序下载

程序下载过程同1.3一致。

7.4 结果展示

  • 待上传视频

7.5 常见问题及解决办法

8. 单片机IO扩展–74HC595

8.1 代码

/*********************
点阵LED实验
实验现象:下载程序后,
点阵LED灯从左往右依次点
亮,类似流水灯效果
日期:2020-04-14
作者:lixs
**********************/

#include 
#include 
typedef unsigned int uint16;//对数据类型进行声明定义
typedef unsigned char uchar8;//对数据类型进行声明定义
uchar8 ledNum;
//**定义IO口**//
sbit SRCLK=P3^6;
sbit RCLK=P3^5;
sbit SER=P3^4;
sbit LED=P0^7;


//**声明函数**//
void Hc595SendByte(uchar8 dat);//声明发送数据函数
void delay(uint16);//声明延时函数

													
void main()
{
		LED = 0;
    ledNum = 0x01;//0000 0001
    while(1)
    {
        Hc595SendByte(ledNum);
        ledNum = _crol_(ledNum,1);//0000 0010
        delay(50000);	
    }		
}

void Hc595SendByte(uchar8 dat)//向74H595发送一个字节数据
{
	uchar8 a;
	SRCLK = 1;
  RCLK = 1;

	for (a = 0; a < 8; a++)
	{
			SER = dat >> 7;//将dat中的最高位D7位赋给SER
			dat <<= 1;//左移将dat中的最高位去掉,用D6位取代D7位

			SRCLK = 0;//移位时钟
			_nop_();
			_nop_();
			SRCLK = 1;//移位时钟
	}
	RCLK = 0;//储存寄存器的时钟
	_nop_();//51中的延时指令,延时一个机器周期,大约1us
	_nop_();//51中的延时指令,延时一个机器周期,大约1us
	RCLK = 1;//储存寄存器的时钟,一个上升沿将数据存在存储寄存器内
}


void delay(uint16 x)//延时函数,x=1时大约延时10us
{
	while(x--); 
}


8.2 编译

编译过程同1.2一致。

8.3 程序下载

程序下载过程同1.3一致。

8.4 结果展示

  • 待上传视频

8.5 常见问题及解决办法

9. LED点阵(点亮一个点)

9.1 代码

/*********************
点阵LED实验
实验现象:下载程序后,
点阵LED灯第一个点亮
日期:2020-04-14
作者:lixs
**********************/

#include 
#include 
typedef unsigned int uint16;//对数据类型进行声明定义
typedef unsigned char uchar8;//对数据类型进行声明定义
uchar8 Num;
//**定义IO口**//
sbit SRCLK=P3^6;
sbit RCLK=P3^5;
sbit SER=P3^4;
sbit LED=P0^7;


//**声明函数**//
void Hc595SendByte(uchar8 dat);//声明发送数据函数


													
void main()
{
		
	LED = 0;
	Num = 0x01;
    while(1)
    {
        Hc595SendByte(Num);
    }		
}

void Hc595SendByte(uchar8 dat)//向74H595发送一个字节数据
{
	uchar8 a;
	SRCLK = 1;
  RCLK = 1;

	for (a = 0; a < 8; a++)
	{
			SER = dat >> 7;//将dat中的最高位D7位赋给SER
			dat <<= 1;//左移将dat中的最高位去掉,用D6位取代D7位

			SRCLK = 0;//移位时钟
			_nop_();
			_nop_();
			SRCLK = 1;//移位时钟
	}
	RCLK = 0;//储存寄存器的时钟
	_nop_();//51中的延时指令,延时一个机器周期,大约1us
	_nop_();//51中的延时指令,延时一个机器周期,大约1us
	RCLK = 1;//储存寄存器的时钟,一个上升沿将数据存在存储寄存器内
}

9.2 编译

编译过程同1.2一致。

9.3 程序下载

程序下载过程同1.3一致。

9.4 结果展示

  • 待上传视频

9.5 常见问题及解决办法

10. LED点阵(显示数字)

10.1 代码

/*********************
点阵LED(点亮数字)实验
实验现象:下载程序后,
点阵LED显示数字0
日期:2020-04-16
作者:lixs
**********************/

#include 
#include 
typedef unsigned int uint16;//对数据类型进行声明定义
typedef unsigned char uchar8;//对数据类型进行声明定义
#define LED P0
uchar8 ledduan[]= {0x00,0x00,0x3C,0x42,0x42,0x3C,0x00,0x00};//段选,即行,数字0
//uchar8 ledduan[]= {0x38,0x7C,0x7E,0x3F,0x3F,0x7E,0x7C,0x38};//段选,即行,心形
uchar8 ledwei[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//位选,即列
//**定义IO口**//
sbit SRCLK=P3^6;
sbit RCLK=P3^5;
sbit SER=P3^4;

void Hc595SendByte(uchar8 dat);
void delay(uint16 x);

	
void main()
{
	uchar8 i=0;
	while(1)
	{
		for(i=0;i<8;i++)
		{
			
			LED=ledwei[i];
			Hc595SendByte(ledduan[i]);
			delay(10);	
			Hc595SendByte(0x00);//消隐
		}
	}
}

void Hc595SendByte(uchar8 dat)//向74H595发送一个字节数据
{
	uchar8 a;
	SRCLK = 1;
  RCLK = 1;

	for (a = 0; a < 8; a++)
	{
			SER = dat >> 7;//将dat中的最高位D7位赋给SER
			dat <<= 1;//左移将dat中的最高位去掉,用D6位取代D7位

			SRCLK = 0;//移位时钟
			_nop_();
			_nop_();
			SRCLK = 1;//移位时钟
	}
	RCLK = 0;//储存寄存器的时钟
	_nop_();//51中的延时指令,延时一个机器周期,大约1us
	_nop_();//51中的延时指令,延时一个机器周期,大约1us
	RCLK = 1;//储存寄存器的时钟,一个上升沿将数据存在存储寄存器内
}

void delay(uint16 x)//延时函数,x=1时大约延时10us
{
	while(x--); 
}

10.2 编译

编译过程同1.2一致。

10.3 程序下载

程序下载过程同1.3一致。

10.4 结果展示

  • 待上传视频

10.5 常见问题及解决办法

11. 直流电机

11.1 代码

/*********************
独立开关控制直流电机实验
实验现象:下载程序后,按
下独立按键,电机旋转
日期:2020-04-16
作者:lixs
**********************/
#include 
#include 
typedef unsigned int uint16;
typedef unsigned char uchar8;
sbit k1=P3^1;//将单片机P3.1端口定义为k1
sbit moto=P1^0;
void delay(uint16 x);
void keypros();

void main()
{
	
	moto=0;//关闭电机
	while(1)
	{
		keypros();
	}
}

void keypros()			//按键处理函数
{
	if(k1==0)				//检测按键是否按下
	{
		delay(1000);//延时10ms,消除抖动
		if(k1==0)
		{
			
			moto=~moto;//moto状态取反
		}
		while(!k1);	/*!k1 = !k1==1 = k1==0 检测按键是否松开,
								如k1=0则表示还没松开,保持在当前循环,
								k1=1则表示松开,跳出当前循环等待下次状态变化*/
	}
	
}

void delay(uint16 x)//延时函数,x=1时大约延时10us
{
	while(x--); 
}

11.2 编译

编译过程同1.2一致。

11.3 程序下载

程序下载过程同1.3一致。

11.4 结果展示

  • 待上传视频

11.5 常见问题及解决办法

12. 外部中断0

12.1 代码

/*********************
外部中断0实验
实验现象:下载程序后,操
作K3按键使D1状态取反
日期:2020-04-17
作者:lixs
**********************/
#include 

typedef unsigned int uint16;
typedef unsigned char uchar8;

sbit k3=P3^2;//定义K3按键
sbit LED=P2^0;//定义P2.0口是LED

void delay(uint16 x)//延时函数
{
	while(x--);
}

void Int0Init()//外部中断0设置
{
	//设置INT0
	IT0=1;//跳变沿触发方式(下降沿)
	EX0=1;//打开INT0的中断允许
	EA=1;//打开总中断
}

void main()//主函数
{
	Int0Init();//设置外部中断0
	while(1);
}

void Int0() interrupt 0  //外部中断0函数
{
	delay(1000);//延时消抖
	if(k3==0)//按键触发
	{
		LED=~LED;
	}
}

12.2 编译

编译过程同1.2一致。

12.3 程序下载

程序下载过程同1.3一致。

12.4 结果展示

  • 待上传视频

12.5 常见问题及解决办法

13. 定时器0中断

13.1 代码

/*********************
定时器0中断实验
实验现象:下载程序后,
D1灯循环点亮1秒,熄灭1秒
日期:2020-04-18
作者:lixs
**********************/
#include 

typedef unsigned int uint16;
typedef unsigned char uchar8;

sbit LED=P2^0;//定义P2.0口是LED
sbit buzzer=P1^5;//将单片机P1.5端口定义为buzzer

void Timer0Init()
{
	TMOD=0x01;//选择为定时器0模式,工作方式1,仅用TR0打开启动
	ET0=1;
	EA=1;
	TR0=1;
}

void main()
{
	Timer0Init();
	while(1);
}

void Timer0() interrupt 1
{
	static uint16 i;
	TH0=0xFC;
	TL0=0x18;
	i++;
	if(i==1000)
	{
		i=0;
		LED=~LED;
	}
}

13.2 编译

编译过程同1.2一致。

13.3 程序下载

程序下载过程同1.3一致。

13.4 结果展示

  • 待上传视频

13.5 常见问题及解决办法

14. 串口通信

14.1 代码

#include 

typedef unsigned int u16;
typedef unsigned char u8;

void UsartInit()
{
	TMOD=0X20;				//设置计数器工作方式2
	TH1=0XFA;					//初始赋值,波特率9600
	TL1=0XFA;					//初始赋值,波特率9600
	PCON=0X80;				//波特率加倍
	TR1=1;						//打开计数器
	SCON=0X50;				//串口工作方式
	ES=1;							//串口中断打开
	EA=1;							//总中断打开	
}

void main()
{
	UsartInit();
	while(1);
}

void Usart() interrupt 4
{
	u8 receiveData;

	receiveData=SBUF;	//出去接收到的数据
	RI = 0;						//清除接收中断标志位
	SBUF=receiveData;	//将接收到的数据放入到发送寄存器
	while(!TI);			 	//等待发送数据完成
	TI=0;						 	//清除发送完成标志位
}

14.2 编译

编译过程同1.2一致。

14.3 程序下载

程序下载过程同1.3一致。

14.4 结果展示

  • 待上传视频

14.5 常见问题及解决办法

15. EEPROM-IIC

15.1 代码

/*********************
i2c驱动程序
实验现象:
日期:2020-04-18
作者:lixs
**********************/

#include "i2c.h"

//延时函数
void Delay10us()
{
	unsigned char a,b;
	for(b=1;b>0;b--)
		for(a=2;a>0;a--);
}

//i2c启动函数
void I2cStart()
{
	SDA=1;
	Delay10us();
	SCL=1;
	Delay10us();
	SDA=0;
	Delay10us();
	SCL=0;
	Delay10us();
}

//i2c终止函数
void I2cStop()
{
	SDA=0;
	Delay10us();
	SCL=1;
	Delay10us();
	SDA=1;
	Delay10us();

}

//i2c发送数据函数
unsigned char I2cSendByte(unsigned char dat)
{
	unsigned char a=0,b=0;
	for(a=0;a<8;a++)
	{
		SDA=dat>>7;
		dat=dat<<1;
		Delay10us();
		SCL=1;
		Delay10us();
		SCL=0;
		Delay10us();
	}
	SDA=1;
	Delay10us();
	SCL=1;
	while(SDA)
	{
		b++;
		if(b>200)
		{
			SCL=0;
			Delay10us();
			return 0;
		}
	}
	SCL=0;
	Delay10us();
	return 1;
}


//i2c读取数据函数
unsigned char I2cReadByte()
{
	unsigned char a=0,dat=0;
	SDA=1;
	Delay10us();
	for(a=0;a<8;a++)
	{
		SCL=1;
		Delay10us();
		dat<<=1;
		dat|=SDA;
		Delay10us();
		SCL=0;
		Delay10us();
	}
	return dat;
}

//往24c02的一个地址写入一个数据
void At24c02Write(unsigned char addr,unsigned char dat)
{
	I2cStart();
	I2cSendByte(0xa0);
	I2cSendByte(addr);
	I2cSendByte(dat);
	I2cStop();
}

//读取24c02的一个地址的一个数据
unsigned char At24c02Read(unsigned char adrr)
{
	unsigned char num;
	I2cStart();
	I2cSendByte(0xa0);
	I2cSendByte(adrr);
	I2cStart();
	I2cSendByte(0xa1);
	num=I2cReadByte();
	I2cStop();
	return num;	
}
/*********************
i2c头文件
实验现象:
日期:2020-04-18
作者:lixs
**********************/

#ifndef _I2C_H_
#define _I2C_H_

#include 

sbit SCL=P2^1;
sbit SDA=P2^0;

void I2cStart();
void I2cStop();
unsigned char I2cSendByte(unsigned char dat);
unsigned char I2cReadByte();
void At24c02Write(unsigned char addr,unsigned char dat);
unsigned char At24c02Read(unsigned char adrr);

#endif
/*********************
i2c实验
实验现象:下载程序后,
数码管后4位显示0,按下
k1保存显示的数据,按下k2
读取上次保存的数据,按下
k3显示数据加1,按下k4显示
数据清零。最大能写入的数据
是255
日期:2020-04-18
作者:lixs
**********************/

#include 
#include "i2c.h"

typedef unsigned int uint16;
typedef unsigned char uchar8;

sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;

char num=0;
uchar8 disp[4];
uchar8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

void delay(uint16 x)
{
	while(x--);
}

//按键处理函数
void Keypros()
{
	if(k1==0)
	{
		delay(1000);
		if(k1==0)
		{
			At24c02Write(1,num);
		}
		while(!k1);
	}
	
	if(k2==0)
	{
		delay(1000);
		if(k2==0)
		{
			num=At24c02Read(1);
		}
		while(!k2);
	}
	
	if(k3==0)
	{
		delay(1000);
		if(k3==0)
		{
			num++;
			if(num>255) num=0;
		}
		while(!k3);
	}
	
	if(k4==0)
	{
		delay(1000);
		if(k4==0)
		{
			num=0;
		}
		while(!k4);
	}
}

//数据处理函数
void datapros()
{
	disp[0]=smgduan[num/1000];//千位
	disp[1]=smgduan[num%1000/100];//百位
	disp[2]=smgduan[num%1000%100/10];//十位
	disp[3]=smgduan[num%1000%100%10];//个位
}

//数码管显示函数
void DigDisplay()
{
	uchar8 i;
	for(i=0;i<4;i++)
	{
		switch(i)  //位选,选择点亮的数码管
		{
			case(0):LSA=1;LSB=1;LSC=0;break;//显示第0位
			case(1):LSA=0;LSB=1;LSC=0;break;//显示第1位
			case(2):LSA=1;LSB=0;LSC=0;break;//显示第2位
			case(3):LSA=0;LSB=0;LSC=0;break;//显示第3位
		}
		P0=disp[i];//发送段选,即选择显示数字几
		delay(100);//延时函数,大约延时1ms
		P0=0x00;//消隐
	}
}

void main()
{
	while(1)
	{
		Keypros();
		datapros();
		DigDisplay();
	}
}

15.2 编译

编译过程同1.2一致。

15.3 程序下载

程序下载过程同1.3一致。

15.4 结果展示

  • 待上传视频

15.5 常见问题及解决办法

16. DS18B20温度传感器

16.1 代码

初始化函数

#include "temp.h"

//延时函数
void Delay1ms(uint y)
{
	uint x;
	for(;y>0;y--)
	{
		for(x=110;x>0;x--);
	}
}

//初始化函数
uchar Ds18b20Init()
{
	uchar i;
	DSPORT=0;//将总线拉低
	i=70;
	while(i--);//延时642us
	DSPORT=1;//然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低
	i=0;
	while(DSPORT)
	{
		Delay1ms(1);
		i++;
		if(i>5)//等待>5ms
		{
			return 0;//初始化失败
		}
	}
	return 1;//初始化成功
	
}

//向18B20写入一个字节
void Ds18b20WriteByte(uchar dat)
{
	uint i,j;
	for(j=0;j<8;j++)
	{
		DSPORT=0;//每写入一位数据之前先把总线拉低1us
		i++;
		DSPORT=dat & 0x01;//然后写入一个数据,从最低位开始
		i=6;
		while(i--);//延时68us,持续时间最少60us
		DSPORT=1;//然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值
		dat>>=1;		
	}
}

//读取一个字节
uchar Ds18b20ReadByte()
{
	uchar byte,bi;
	uint i,j;
	for(j=8;j>0;j--)
	{
		DSPORT=0;//先将总线拉低1us
		i++;
		DSPORT=1;//然后释放总线
		i++;
		i++;//延时6us等待数据稳定
		bi=DSPORT;//读取数据,从最低位开始读取
		//将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0
		byte=(byte>>1)|(bi<<7);
		i=4;//读取完之后等待48us再接着读取下一个数
		while(i--);
	}
return byte;
}

//让18b20开始转换温度
void Ds18b20ChangTemp()
{
	Ds18b20Init();
	Delay1ms(1);
	Ds18b20WriteByte(0xcc);//跳过ROM操作指令
	Ds18b20WriteByte(0x44);//温度转换命令
	//Delay1ms(100);//等待转换成功,而如果你是一只刷着的话,就不用这个延时了
}

//发送读取温度命令
void Ds18b20ReadTempCom()
{
	Ds18b20Init();
	Delay1ms(1);
	Ds18b20WriteByte(0xcc);//跳过ROM操作指令
	Ds18b20WriteByte(0xbe);//温度转换命令
}

//读取温度
int Ds18b20ReadTemp()
{
	int temp=0;
	uchar tmh,tml;
	Ds18b20ChangTemp();//先写入转换命令
	Ds18b20ReadTempCom();//然后等待转换完成后发送读取温度命令
	tml=Ds18b20ReadByte();//读取温度值共16位,先读低字节
	tmh=Ds18b20ReadByte();//再读高字节
	temp=tmh;
	temp<<=8;
	temp|=tml;
	return temp;
	
}

主函数

/*********************
DS18b02温度传感器实验
实验现象:下载程序后,数码管会显示检测到的温度值
日期:2020-04-20
作者:lixs
**********************/

#include 
#include "temp.h"

typedef unsigned int u16;
typedef unsigned char u8;

sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

char num=0;
u8 DisplayData[8];
u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

//延时函数
void delay(u16 i)
{
	while(i--);
}

//温度读取处理转换函数
void datapros(int temp)
{
	float tp;
	if(temp<0)//当温度值为负
	{
		DisplayData[0]=0x40;
		//因为读取的温度是实际温度的补码,所以减1,再取反求出源码
		temp=temp-1;
		temp=~temp;
		tp=temp;
		temp=tp*0.0625*100+0.5;//留两个小数点就是*100,+0.5就是四舍五入
	}
	else
	{
		DisplayData[0]=0x00;
		tp=temp;
		temp=tp*0.0625*100+0.5;
	}
	DisplayData[1]=smgduan[temp%10000/1000];
	DisplayData[2]=smgduan[temp%1000/100];
	DisplayData[3]=smgduan[temp%100/10];
	DisplayData[4]=smgduan[temp%10/1];
}

//数码管显示函数
void DigDisplay()
{
	u8 i;
	for(i=0;i<6;i++)
	{
		switch(i)
		{
			case(0):LSA=1;LSB=1;LSC=1;break;//显示第0位
			case(1):LSA=0;LSB=1;LSC=1;break;//显示第1位
			case(2):LSA=1;LSB=0;LSC=1;break;//显示第2位
			case(3):LSA=0;LSB=0;LSC=1;break;//显示第3位
			case(4):LSA=1;LSB=1;LSC=0;break;//显示第4位
			case(5):LSA=0;LSB=1;LSC=0;break;//显示第5位
		}
		P0=DisplayData[i];//发送数据
		delay(100);
		P0=0x00;
	}
}

//主函数
void main()
{
	while(1)
	{
		datapros(Ds18b20ReadTemp());//数据处理函数
		DigDisplay();//数码管显示函数
	}
}

头文件

#ifndef _TEMP_H_
#define _TEMP_H_

#include 

//重定义关键字
#ifndef uchar
#define uchar unsigned char 
#endif

#ifndef uint 
#define uint unsigned int
#endif

//定义使用的IO口
sbit DSPORT=P3^7;

//声明全局函数
void Delay1ms(uint y);
uchar Ds18b20Init();
void Ds18b20WriteByte(uchar dat);
uchar Ds18b20ReadByte();
void Ds18b20ChangTemp();
void Ds18b20ReadTempCom();
int Ds18b20ReadTemp();

#endif

16.2 编译

编译过程同1.2一致。

16.3 程序下载

程序下载过程同1.3一致。

16.4 结果展示

  • 待上传视频

16.5 常见问题及解决办法

17. DS1302时钟

17.1 代码

初始化函数

#include "ds1302.h"

//DS1302写入和读取时分秒的地址命令
//秒分时日月周年最低位读写位
uchar code READ_RTC_ADDR[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};//读地址{秒,分,小时,日,月,星期,年}
uchar code WRITE_RTC_ADDR[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};//写地址{秒,分,小时,日,月,星期,年}

//DS1302时钟初始化2016年5月7日星期六12点00分00秒
//存储顺序是秒分时日月周年,存储格式是用BCD码
uchar  TIME[7]={0,0,0x12,0x07,0x05,0x06,0x16};//{秒,分,时,日,月,星期,年}

//单片机向DS1302发送(地址+数据)
void Ds1302Write(uchar addr,uchar dat)
{
	uchar n;
	RST=0;
	_nop_();
	
	SCLK=0;//先将SCLK置于低电平
	_nop_();
	RST=1;//然后将RST(CE)置高电平
	_nop_();
	
	for(n=0;n<8;n++)//开始传送8位地址命令
	{
		DSIO=addr & 0x01;//数据从低位开始传送
		addr>>=1;
		SCLK=1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK=0;
		_nop_();	
	}
	
	for(n=0;n<8;n++)
	{
		DSIO=dat & 0x01;
		dat>>=1;
		SCLK=1;
		_nop_();
		SCLK=0;
		_nop_();
	}
	
	RST=0;//传送数据结束
	_nop_();	
}

//读取一个地址的数据
uchar Ds1302Read(uchar addr)
{
	uchar n,dat,dat1;
	RST=0;
	_nop_();
	
	SCLK=0;
	_nop_();
	RST=1;
	_nop_();
	
	for(n=0;n<8;n++)//开始传送8位地址命令
	{
		DSIO=addr & 0x01;//数据从低位开始传送
		addr>>=1;
		SCLK=1;//数据在上升沿时,DS1302读取数据
		_nop_();
		SCLK=0;
		_nop_();//数据在下降沿时,放置数据	
	}
	_nop_();
	for(n=0;n<8;n++)//读取8位数据
	{
		dat1=DSIO;//从最低位开始接收,DISO从低位开始依次发送8位数据*********
		dat=(dat>>1)|(dat1<<7);//将DSIO的最低位左移7位至最高位,然后将dat右移1位,
		//即最高位置0,即可将DSIO的最高位放置dat中,循环8次即可将addr数据放置dat中		
		SCLK=1;
		_nop_();
		SCLK=0;
		_nop_();
	}
	RST=0;
	_nop_();//以下为DS1302复位的稳定时间
	SCLK=1;
	_nop_();
	DSIO=0;
	_nop_();
	DSIO=1;
	_nop_();
	return dat;
}


//初始化DS1302
void Ds1302Init()
{
	uchar n;
	Ds1302Write(0x8e,0x00);//关闭写保护功能
	for(n=0;n<7;n++)
	{
		Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);
	}
	Ds1302Write(0x8e,0x80);//打开写保护
}

//读取时钟信息
void Ds1302ReadTime()
{
	uchar n;
	for(n=0;n<7;n++)//读取7个字节的时钟信号:分秒时日月周年
	{
		TIME[n]=Ds1302Read(READ_RTC_ADDR[n]);
	}
}

主函数

/*********************
DS1302时钟实验
实验现象:下载程序后,数码管会显示时钟
日期:2020-04-21
作者:lixs
**********************/

#include 
#include "ds1302.h"

typedef unsigned int u16;
typedef unsigned char u8;

sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

char num=0;
u8 DisplayData[8];
u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

//延时函数
void delay(u16 i)
{
	while(i--);
}

//时间读取处理转换函数
void datapros()
{
	Ds1302ReadTime();
	DisplayData[0]=smgduan[TIME[2]/16];//时
	DisplayData[1]=smgduan[TIME[2]&0x0f];
	DisplayData[2]=0x40;
	DisplayData[3]=smgduan[TIME[1]/16];//分
	DisplayData[4]=smgduan[TIME[1]&0x0f];
	DisplayData[5]=0x40;
	DisplayData[6]=smgduan[TIME[0]/16];//秒
	DisplayData[7]=smgduan[TIME[0]&0x0f];
}

//数码管显示函数
void DigDisplay()
{
	u8 i;
	for(i=0;i<8;i++)
	{
		switch(i)
		{
			case(0):LSA=1;LSB=1;LSC=1;break;//显示第0位
			case(1):LSA=0;LSB=1;LSC=1;break;//显示第1位
			case(2):LSA=1;LSB=0;LSC=1;break;//显示第2位
			case(3):LSA=0;LSB=0;LSC=1;break;//显示第3位
			case(4):LSA=1;LSB=1;LSC=0;break;//显示第4位
			case(5):LSA=0;LSB=1;LSC=0;break;//显示第5位
			case(6):LSA=1;LSB=0;LSC=0;break;//显示第6位
			case(7):LSA=0;LSB=0;LSC=0;break;//显示第7位
			
		}
		P0=DisplayData[i];//发送数据
		delay(100);
		P0=0x00;
	}
}

//主函数
void main()
{
	Ds1302Init();
	while(1)
	{
		datapros();//数据处理函数
		DigDisplay();//数码管显示函数
	}
}

头文件

#ifndef _DS1302_H_
#define _DS1302_H_


//包含头文件
#include 
#include 


//重定义关键词
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint
#define uint unsigned int
#endif

//定义ds1302的IO口
sbit DSIO=P3^4;
sbit RST=P3^5;
sbit SCLK=P3^6;

//定义全局函数
void Ds1302Write(uchar addr,uchar dat);
uchar Ds1302Read(uchar addr);
void Ds1302Init();
void Ds1302ReadTime();

//加入全局变量
extern uchar TIME[7];

#endif

17.2 编译

编译过程同1.2一致。

17.3 程序下载

程序下载过程同1.3一致。

17.4 结果展示

  • 待上传视频

17.5 常见问题及解决办法

18. AD模数转换

18.1 代码

初始化函数

#include "XPT2046.h"

//使用SPI写入数据
void SPI_Write(uchar dat)
{
	uchar i;
	CLK=0;
	for(i=0;i<8;i++)
	{
		DIN=dat>>7;//放置最高位 
		dat<<=1;
		CLK=0;
		CLK=1;
		
	}
}

//使用SPI读数据
uint SPI_Read(void)
{
	uint i,dat=0;
	CLK=0;
	for(i=0;i<12;i++)
	{
		dat<<=1;
		CLK=1;
		CLK=0;
		dat|=DOUT;
		
	}
	return dat;
}

//读取电位器数据
uint Read_AD_Data(uchar cmd)
{
	uchar i;
	uint AD_Value;
	CLK=0;
	CS=0;
	SPI_Write(cmd);
	for(i=6;i>0;i--);//延时等待转换结果
	CLK=1;//发送一个时钟周期,清楚BUSY
	_nop_();
	_nop_();
	CLK=0;
	_nop_();
	_nop_();
	AD_Value=SPI_Read();
	CS=1;
	return AD_Value;
}

主函数

/*********************
AD模数转换实验
实验现象:下载程序后,
数码管前4位显示电位器检测
的AD值,范围是0-4095
日期:2020-04-28
作者:lixs
**********************/

#include 
#include "XPT2046.h"

typedef unsigned int u16;
typedef unsigned char u8;

sbit LSA=P2^2;//将单片机P2.2端口定义为LSA
sbit LSB=P2^3;//将单片机P2.3端口定义为LSB
sbit LSC=P2^4;//将单片机P2.4端口定义为LSC
u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,
										 0x6d,0x7d,0x07,0x7f,0x6f,
										 0x77,0x7c,0x39,0x5e,0x79,0x71};//段选显示0-F的值
u8 disp[4];


//延时函数
void delay(u16 i)
{
	while(i--);
}

//数据处理函数
void datapros()
{
	u16 ADC_Value;
	float ADC_Voltage;
	static u8 i;
	if(i==50)
	{
		i=0;
		ADC_Value=Read_AD_Data(0x94);
		ADC_Voltage=(2.5*(float)ADC_Value)/4096;//将读取到的值转换为电压值
	}
	i++;
	/*disp[0]=smgduan[temp/1000];//千位
	disp[1]=smgduan[temp%1000/100];//百位
	disp[2]=smgduan[temp%1000%100/10];//十位
	disp[3]=smgduan[temp%1000%100%10];//个位*/
	
	disp[0]=smgduan[(u8)(ADC_Voltage*100)/1000];//千位
	disp[1]=smgduan[(u8)(ADC_Voltage*100)%1000/100];//百位
	disp[2]=smgduan[(u8)(ADC_Voltage*100)%1000%100/10];//十位
	disp[3]=smgduan[(u8)(ADC_Voltage*100)%1000%100%10];//个位
}

//数码管显示函数
void DigDisplay()//位选、段选函数,即选择点亮第几个数码管,并显示数字几
{
	u8 i;
	for(i=0;i<4;i++)
	{
		switch(i)
		{
			case(0):LSA=1;LSB=1;LSC=1;break;//显示第0位,即点亮LED8,左1
			case(1):LSA=0;LSB=1;LSC=1;break;//显示第1位,即点亮LED7,左2
			case(2):LSA=1;LSB=0;LSC=1;break;//显示第2位,即点亮LED6,左3
			case(3):LSA=0;LSB=0;LSC=1;break;//显示第3位,即点亮LED5,左4	
		}
		P0=disp[i];//发送段选数据
		delay(100);//延时函数,大约延时1ms
		P0=0x00;//消隐
	}
}

//主函数
void main()
{
	while(1)
	{
		datapros();
		DigDisplay();
	}
}

头文件

#ifndef _XPT2046_H_
#define _XPT2046_H_

//包含头文件
#include 
#include 

//重定义关键词
#ifndef uchar
#define uchar unsigned char 
#endif

#ifndef uint
#define uint unsigned int 
#endif

#ifndef ulong
#define ulong unsigned long 
#endif

//定义使用的IO口
sbit DOUT = P3^7;	//输出
sbit CLK = P3^6;	//时钟
sbit DIN = P3^4;	//输入
sbit CS = P3^5;	//片选

uint Read_AD_Data(uchar cmd);
uint SPI_Read(void);
void SPI_Write(uchar dat);

#endif

18.2 编译

编译过程同1.2一致。

18.3 程序下载

程序下载过程同1.3一致。

18.4 结果展示

  • 待上传视频

18.5 常见问题及解决办法

1、怎么把读取到的数值转为电压值?
答:ADC_Voltage=ADC_Value*2.5/4096,ADC_Value为读到的数值,2.5为参考电压,4096为2^12(根据分辨率决定)。
2、注意进行电压转换时,ADC_Voltage和ADC_Value需要为浮点型数据。

19. DA数模转换

19.1 代码

/*********************
DA数模转换实验
实验现象:下载程序后,
DA模块上的DA1指示灯呈
呼吸灯效果,由暗变亮再
由亮变暗
日期:2020-04-29
作者:lixs
**********************/

#include 

typedef unsigned int u16;
typedef unsigned char u8;

sbit PWM=P2^1;
bit DIR;

u16 count,value,timer1;

//定时器1初始化
void Timer1Init()
{
	TMOD|=0X10;//选择为定时器1模式,工作方式1,仅用TR1打开启动
	
	TH1=0XFF;
	TL1=0XFF;
	
	ET1=1;//打开定时器1中断允许
	EA=1;//打开总中断
	TR1=1;//打开定时器
}

//主函数
void main()
{
	Timer1Init();//定时器初始化
	while(1)
	{
		if(count>100)	//100*1us=0.1ms					计时100次后value开始++,此时value
		{
			count=0;
			if(DIR==1)
			{
				value++;
			}
			if(DIR==0)																	
			{
				value--;
			}
		}
		
		if(value==1000)
		{
			DIR=0;
		}
		if(value==0)
		{
			DIR=1;
		}
		
		if(timer1>1000)//PWM周期为1000*1us=1ms
		{
			timer1=0;
		}
		if(timer1<value)
		{
			PWM=1;
		}
		else
		{
			PWM=0;
		}
	}
}

//定时器的中断函数
void Time1(void) interrupt 3
{
	TH1=0XFF;
	TL1=0XFF;
	timer1++;
	count++;
}

19.2 编译

编译过程同1.2一致。

19.3 程序下载

程序下载过程同1.3一致。

19.4 结果展示

  • 待上传视频

19.5 常见问题及解决办法

20. LCD1602液晶

20.1 代码

初始化函数

#include "lcd.h"

//延时函数
void Lcd1602_Delay1ms(uint c)
{
	uchar a,b;
	for(;c>0;c--)
	{
		for(b=199;b>0;b--)
		{
			for(a=1;a>0;a--);
		}
	}
}

//向LCD写入一个字节的命令
#ifndef LCD1602_4PINS
void LcdWriteCom(uchar com)
{
	LCD1602_E=0;		//使能
	LCD1602_RS=0;		//选择发送命令
	LCD1602_RW=0;		//选择写入
	
	LCD1602_DATAPINS=com;		//放入命令
	Lcd1602_Delay1ms(1);		//等待数据稳定
	
	LCD1602_E=1;		//写入时序
	Lcd1602_Delay1ms(5);		//保持时间
	LCD1602_E=0;
}
#else
void LcdWriteCom(uchar com)
{
	LCD1602_E=0;		//使能
	LCD1602_RS=0;		//选择发送命令
	LCD1602_RW=0;		//选择写入
	
	LCD1602_DATAPINS=com;		//放入命令
	Lcd1602_Delay1ms(1);		//等待数据稳定
	
	LCD1602_E=1;		//写入时序
	Lcd1602_Delay1ms(5);		//保持时间
	LCD1602_E=0;
	
	LCD1602_DATAPINS=com<<4;		//发送低四位
	Lcd1602_Delay1ms(1);
	
	LCD1602_E=1;		//写入时序
	Lcd1602_Delay1ms(5);		//保持时间
	LCD1602_E=0;
}
#endif

//向LCD写入一个字节的数据
#ifndef LCD1602_4PINS
void LcdWriteData(uchar dat)
{
	LCD1602_E=0;		//使能
	LCD1602_RS=1;		//选择输入数据
	LCD1602_RW=0;		//选择写入
	
	LCD1602_DATAPINS=dat;		//写入数据
	Lcd1602_Delay1ms(1);		//等待数据稳定
	
	LCD1602_E=1;		//写入时序
	Lcd1602_Delay1ms(5);		//保持时间
	LCD1602_E=0;
}
#else
void LcdWriteData(uchar dat)
{
	LCD1602_E=0;		//使能
	LCD1602_RS=1;		//选择写入数据
	LCD1602_RW=0;		//选择写入
	
	LCD1602_DATAPINS=dat;		//放入命令
	Lcd1602_Delay1ms(1);		//等待数据稳定
	
	LCD1602_E=1;		//写入时序
	Lcd1602_Delay1ms(5);		//保持时间
	LCD1602_E=0;
	
	LCD1602_DATAPINS=dat<<4;		//发送低四位
	Lcd1602_Delay1ms(1);
	
	LCD1602_E=1;		//写入时序
	Lcd1602_Delay1ms(5);		//保持时间
	LCD1602_E=0;
}
#endif

//初始化LCD屏
#ifndef LCD1602_4PINS
void LcdInit()
{
	LcdWriteCom(0x38);		//开显示
	LcdWriteCom(0x0c);		//开显示不显示光标
	LcdWriteCom(0x06);		//写一个指针加1
	LcdWriteCom(0x01);		//清屏
	LcdWriteCom(0x80);		//设置数据指针起点
}
#else
void LcdInit()
{
	LcdWriteCom(0x32);		//将8位总线转为4位总线
	LcdWriteCom(0x28);		//在四位线下的初始化
	LcdWriteCom(0x0c);		//开显示不显示光标
	LcdWriteCom(0x06);		//写一个指针加1
	LcdWriteCom(0x01);		//清屏
	LcdWriteCom(0x80);		//设置数据指针起点
}
#endif

主函数

/*********************
LCD1602液晶实验
实验现象:下载程序后,插
上LCD1602液晶,即可显示Hello World
日期:2020-04-29
作者:lixs
**********************/

#include "reg52.h"
#include "lcd.h"

typedef unsigned int u16;
typedef unsigned char u8;

u8 Disp[]=" Hello World ";


void main()
{
	u8 i;
	LcdInit();
	for(i=0;i<13;i++)
	{
		LcdWriteData(Disp[i]);
	}
	while(1);
}

头文件

#ifndef _LCD_H_
#define _LCD_H_

/*当使用的是4位数据传输的时候定义,使用8位取消这个定义*/
//#define LCD1602_4PINS

#include 

#ifndef uchar
#define uchar unsigned char
#endif 

#ifndef uint
#define uint unsigned int
#endif

#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;

void Lcd1602_Delay1ms(uint c);
void LcdWriteCom(uchar com);
void LcdWriteData(uchar dat);
void LcdInit();

#endif

20.2 编译

编译过程同1.2一致。

20.3 程序下载

程序下载过程同1.3一致。

20.4 结果展示

  • 待上传视频

20.5 常见问题及解决办法

普中51-单核-A2开发板的基础实验例程分享至此结束,本来打算紧接着下一篇做中级实验教程,后来由于工作,间隔了一段时间,感觉基础知识还是没吃透,所以下一篇准备做一下郭天祥的51单片机教程的课后题,温故而知新。因为手里没有开发板,到时会用proteus仿真进行结果展示,我会尽快整理完后分享给大家!(PS:关于本文章的例程结果展示动画,我会尽快补回来!!!)

你可能感兴趣的:(STC89C51入门,单片机,编程语言)