蒟蒻初学单片机的一丢丢笔记

零、引脚

  • 0 宏定义数码管段码口 点阵列控制端口
  • 1 右下角矩阵按键控制口
  • 1.0 直流电机控制管脚
  • 1.0 1.1 1.2 1.3 控制步进电机管脚
  • 2.0 右边的LED
  • 2.1 SCL时钟线 2.0 SDA数据线
  • 2.2 2.3 2.4 左上角的数码管
  • 2.5 蜂鸣器
  • 3.1 3.0 3.2 3.3 左下角的四个独立按键控制脚
  • 3.4 串行数据输入
  • 3.5 存储寄存器时钟输入
  • 3.6 移位寄存器时钟输入

一、跑马灯

/*单个灯闪烁
		LED1=0; //点亮
		delay_10us(50000); //大约延时 4500ms
		LED1=1; //熄灭
		delay_10us(50000);
*/
/*跑马灯
		u8 i;
		for (i = 0; i < 8; i ++)
		{
			LED_PORT = ~(0x01 << i);
			delay_10us(50000);
		}
*/
/*循环跑马灯
		for (i = 1; i < 8; i ++)
		{
			LED_PORT = _crol_(LED_PORT, 1);
			delay_10us();
		}
		for (i = 1; i < 8; i ++)
		{
			LED_PORT = _cror_(LED_PORT, 1);
			delay_10us();
		}
*/

二、蜂鸣

原理:该蜂鸣器是无源的,加上扰动才能发音。

一定要在外面加上while(1),但原因不知道。

		while (i --){
			BEEP = !BEEP;
			delay_10us();
		} 
		i = 0;

三、静态显示

将a~小数点的01写出来后反过来 最顶的是a 他右边的是b 转个圈

只能显示最左边的一个位置

1000 0111 计算时为 1110 1000e1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iolf02To-1655964413878)(https://i.bmp.ovh/imgs/2022/06/20/3b17585168ab885f.png)]

#include "reg52.h"
//#include "intrins.h"

//#define LED_PORT P2 //使用宏定义	LED灯
#define SMG_A_DP_PORT P0 //使用宏定义数码管段码口 左上角的第0个

//sbit LED1=P2^7;
//sbit BEEP=P2^5; //将 P2.5 管脚定义为 BEE 蜂鸣器

typedef unsigned int u16; //对系统默认数据类型进行重命名
typedef unsigned char u8;


void delay_10us()
{
	u16 ten_us = 50000;
	while(ten_us--);
}


void main(){
	//共阴极数码管显示 0~F 的段码数据
	//将a~小数点的01写出来后反过来
	u8 gsmg_code[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
						0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

	u16 i;
	for (i = 0; i < 16; i ++)
	{
	    SMG_A_DP_PORT = gsmg_code[i];//将数组第 1 个数据赋值给数码管段选口
		delay_10us();
	}
	

	while (1)
	{

	}
}

四、动态数码管

似乎只能把三个引脚设为2.2、2.3、2.4

理解成三个引脚合成一个位置。

ABC是234,写的时候以CBA来看。如此时C=0; B=0; A = 1,那么他表示的是从右到左第1个位置。

实现从右往左跑马灯“HELLO WORLD”

/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net

实验名称:动态数码管实验
接线说明:	
实验现象:下载程序后“数码管模块”显示01234567
注意事项:																				  
***************************************************************************************/
#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;

#define SMG_A_DP_PORT	P0	//使用宏定义数码管段码口

//定义数码管位选信号控制脚
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

//HELLO WORLD
u8 gsmg_code[17]={0x76, 0x79, 0x38, 0x38, 0x3f, 0x00, 0x3c, 0x1e, 0x3f, 0x50, 0x38, 0x5e, 0x00, 0x00}; //14

/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名       : smg_display
* 函数功能		 : 动态数码管显示
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void smg_display(void)
{
	u8 i = 0;
	u8 t, k, j;
	u8 show_code[8];
	//HELLO WOrLd 从右到左
	while (1){
		i = (i) % 14;	  //将要加进来的输出数组下标
		
		for (k = 0; k < 7; k ++) show_code[k] = show_code[k + 1];
		show_code[7] = gsmg_code[i ++];

		//每次输出一个长度为8的数组
		t = 100;		
		while (t --)
		{
			for (j = 0; j < 8; j ++)
			{
			   	switch(j)//位选
				{
					case 0: LSC=1;LSB=1;LSA=1;break;
					case 1: LSC=1;LSB=1;LSA=0;break;
					case 2: LSC=1;LSB=0;LSA=1;break;
					case 3: LSC=1;LSB=0;LSA=0;break;
					case 4: LSC=0;LSB=1;LSA=1;break;
					case 5: LSC=0;LSB=1;LSA=0;break;
					case 6: LSC=0;LSB=0;LSA=1;break;
					case 7: LSC=0;LSB=0;LSA=0;break;
				}
				SMG_A_DP_PORT=show_code[j];//传送段选数据
				delay_10us(100);//延时一段时间,等待显示稳定
				SMG_A_DP_PORT=0x00;//消音
			}
		}
		delay_10us(100);
	}	
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	while(1)
	{
	   	smg_display();
	}		
}

五、独立按键

按键被按时被按的变为0,电流变化是输入

/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net

实验名称:独立按键实验
接线说明:	
实验现象:下载程序后,按下“独立按键”模块中K1键,控制D1指示灯亮灭
注意事项:																				  
***************************************************************************************/
#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;

//定义独立按键控制脚
sbit KEY1=P3^1;
sbit KEY2=P3^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;

//定义LED1控制脚
sbit LED1=P2^0;

//使用宏定义独立按键按下的键值
#define KEY1_PRESS	1
#define KEY2_PRESS	2
#define KEY3_PRESS	3
#define KEY4_PRESS	4
#define KEY_UNPRESS	0	

/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名       : key_scan
* 函数功能		 : 检测独立按键是否按下,按下则返回对应键值
* 输    入       : mode=0:单次扫描按键
				   mode=1:连续扫描按键
* 输    出    	 : KEY1_PRESS:K1按下
				   KEY2_PRESS:K2按下
				   KEY3_PRESS:K3按下
				   KEY4_PRESS:K4按下
				   KEY_UNPRESS:未有按键按下
*******************************************************************************/
u8 key_scan(u8 mode)
{
	static u8 key=1;

	if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))//任意按键按下
	{
		delay_10us(1000);//消抖
		key=0;
		if(KEY1==0)
			return KEY1_PRESS;
		else if(KEY2==0)
			return KEY2_PRESS;
		else if(KEY3==0)
			return KEY3_PRESS;
		else if(KEY4==0)
			return KEY4_PRESS;	
	}
	else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1)	//无按键按下
	{
		key=1;			
	}
	return KEY_UNPRESS;		
}
/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	u8 key=0;

	while(1)
	{
	   	key=key_scan(0);
		if(key==KEY1_PRESS)//检测按键K1是否按下
			LED1=!LED1;//LED1状态翻转	
	}		
}

六、矩阵按键

8个I/O口,4行4列

先行后列,从左往右分别代表1234

每加一行加4,结果加列。0表示被按下。

/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net

实验名称:矩阵按键实验
接线说明:
实验现象:下载程序后,按下“矩阵按键”模块中S1-S16键,对应数码管最左边显示0-F
注意事项:
***************************************************************************************/
#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;

#define KEY_MATRIX_PORT	P1	//使用宏定义矩阵按键控制口		

#define SMG_A_DP_PORT	P0	//使用宏定义数码管段码口

//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17] = { 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
				0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71 };

/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while (ten_us--);
}

/*******************************************************************************
* 函 数 名       : key_matrix_flip_scan
* 函数功能		 : 使用线翻转扫描方法,检测矩阵按键是否按下,按下则返回对应键值
* 输    入       : 无
* 输    出    	 : key_value:1-16,对应S1-S16键,
				   0:按键未按下
*******************************************************************************/
u8 key_matrix_flip_scan(void)
{
	static u8 key_value = 0;

	KEY_MATRIX_PORT = 0x0f;//给所有行赋值0,列全为1
	if (KEY_MATRIX_PORT != 0x0f)//判断按键是否按下
	{
		delay_10us(1000);//消抖
		if (KEY_MATRIX_PORT != 0x0f)
		{
			//测试列
			KEY_MATRIX_PORT = 0x0f;
			switch (KEY_MATRIX_PORT)//保存行为0,按键按下后的列值	
			{
			case 0x07: key_value = 1; break;
			case 0x0b: key_value = 2; break;
			case 0x0d: key_value = 3; break;
			case 0x0e: key_value = 4; break;
			}
			//测试行
			KEY_MATRIX_PORT = 0xf0;
			switch (KEY_MATRIX_PORT)//保存列为0,按键按下后的键值	
			{
			case 0x70: key_value = key_value; break;
			case 0xb0: key_value = key_value + 4; break;
			case 0xd0: key_value = key_value + 8; break;
			case 0xe0: key_value = key_value + 12; break;
			}
			while (KEY_MATRIX_PORT != 0xf0);//等待按键松开	
		}
	}
	else
		key_value = 0;

	return key_value;
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{
	u8 key = 0;

	while (1)
	{
		key = key_matrix_flip_scan();
		if (key != 0)
			SMG_A_DP_PORT = gsmg_code[key - 1];//得到的按键值减1换算成数组下标对应0-F段码		
	}
}

七、IO 扩展

右上角的点阵

u8 ghc595_buf[8]={0x01,0x02,0x03,0x0f,0x10,0x20,0x40,0x80};

最下面是0000 0001(0x01),最上面是1000 0000(0x80)

移位寄存器 -> 存储寄存器 传东西

如果两个时钟连在一起,则移位寄存器总是比存储器早一个脉冲

for 循环里面最好不要有等于。可能是精度问题。

将LED点阵列全部设置为0,即LED阴极为低电平,当有1时亮灯。

将移位寄存器和存储器置0置1表示传输数据。

/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net

实验名称:IO扩展(串转并)实验-74HC595
接线说明:	
实验现象:下载程序后,8*8LED点阵以一行循环滚动显示
注意事项:LED点阵旁的J24黄色跳线帽短接到GND一端																				  
***************************************************************************************/
#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;

//定义74HC595控制管脚
sbit SRCLK=P3^6;	//移位寄存器时钟输入
sbit RRCLK=P3^5;		//存储寄存器时钟输入
sbit SER=P3^4; 		//串行数据输入

#define LEDDZ_COL_PORT	P0	//点阵列控制端口

u8 ghc595_buf[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名       : delay_ms
* 函数功能		 : ms延时函数,ms=1时,大约延时1ms
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_ms(u16 ms)
{
	u16 i,j;
	for(i=ms;i>0;i--)
		for(j=110;j>0;j--);
}

/*******************************************************************************
* 函 数 名         : hc595_write_data(u8 dat)
* 函数功能		   : 向74HC595写入一个字节的数据
* 输    入         : dat:数据
* 输    出         : 无
*******************************************************************************/
void hc595_write_data(u8 dat)
{
	u16 i;
	
	//不能在大循环里写上大于等于 推测精度原因
	for(i = 8; i > 0; i--)//循环8次即可将一个字节写入寄存器中
	{
		SER = (dat >> (i - 1)) & 1;//优先传输一个字节中的高位
	//	dat <<= 1;//将低位移动到高位
		SRCLK=0;
		delay_10us(1);
		SRCLK=1;
		delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中	
	}
	RRCLK=0;
	delay_10us(1);
	RRCLK=1;//存储寄存器时钟上升沿将前面写入到寄存器的数据输出	
}


/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	u8 i=0;

	LEDDZ_COL_PORT=0x00;//将LED点阵列全部设置为0,即LED阴极为低电平
	while(1)
	{		
		for(i=0;i<8;i++)
		{	
			hc595_write_data(0x00);//消除前面寄存器缓存数据
			hc595_write_data(ghc595_buf[i]);//写入新的数据
			delay_ms(500);//延时500ms	
		}									
	}		
}

八、LED 点阵实验

8.1 点灯

LEDDZ_COL_PORT=0x00; 设置的是列数。当列数为0时可被点亮、当列数为1时不能被点亮。

/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net

实验名称:LED点阵实验(点亮一个点)
接线说明:
实验现象:下载程序后,8*8LED点阵点亮左上角第一个点
注意事项:LED点阵旁的J24黄色跳线帽短接到GND一端
***************************************************************************************/
#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;

//定义74HC595控制管脚
sbit SRCLK = P3 ^ 6;	//移位寄存器时钟输入
sbit rCLK = P3 ^ 5;		//存储寄存器时钟输入
sbit SER = P3 ^ 4; 		//串行数据输入

#define LEDDZ_COL_PORT	P0	//点阵列控制端口


/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while (ten_us--);
}

/*******************************************************************************
* 函 数 名         : hc595_write_data(u8 dat)
* 函数功能		   : 向74HC595写入一个字节的数据
* 输    入         : dat:数据
* 输    出         : 无
*******************************************************************************/
void hc595_write_data(u8 dat)
{
	u8 i = 0;

	for (i = 0; i < 8; i++)//循环8次即可将一个字节写入寄存器中
	{
		SER = dat >> 7;//优先传输一个字节中的高位
		dat <<= 1;//将低位移动到高位
		SRCLK = 0;
		delay_10us(1);
		SRCLK = 1;
		delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中	
	}
	rCLK = 0;
	delay_10us(1);
	rCLK = 1;//存储寄存器时钟上升沿将前面写入到寄存器的数据输出	
}


/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{
	u8 i = 0;

	LEDDZ_COL_PORT = 0x7f;//将LED点阵左边第一列设置为0,即LED阴极为低电平,其余列为1,即高电平
	while (1)
	{
		hc595_write_data(0x87); //行							
	}
}

8.2 显示数字、图形

每次亮一列,每列的哪几行看着亮。

/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net

实验名称:LED点阵实验(显示数字)
接线说明:	
实验现象:下载程序后,8*8LED点阵显示数字0
注意事项:LED点阵旁的J24黄色跳线帽短接到GND一端																				  
***************************************************************************************/
#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;

//定义74HC595控制管脚
sbit SRCLK=P3^6;	//移位寄存器时钟输入
sbit rCLK=P3^5;		//存储寄存器时钟输入
sbit SER=P3^4; 		//串行数据输入

#define LEDDZ_COL_PORT	P0	//点阵列控制端口

u8 gled_row[8]={0x20,0x7F,0x80,0x49,0x7F,0x49,0x4F,0x01};//LED点阵显示数字0的行数据
u8 gled_col[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//LED点阵显示数字0的列数据

/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名         : hc595_write_data(u8 dat)
* 函数功能		   : 向74HC595写入一个字节的数据
* 输    入         : dat:数据
* 输    出         : 无
*******************************************************************************/
void hc595_write_data(u8 dat)
{
	u8 i=0;
	
	for(i=0;i<8;i++)//循环8次即可将一个字节写入寄存器中
	{
		SER=dat>>7;//优先传输一个字节中的高位
		dat<<=1;//将低位移动到高位
		SRCLK=0;
		delay_10us(1);
		SRCLK=1;
		delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中	
	}
	rCLK=0;
	delay_10us(1);
	rCLK=1;//存储寄存器时钟上升沿将前面写入到寄存器的数据输出	
}


/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	u8 i=0;

	while(1)
	{			
		for(i=0;i<8;i++)//循环8次扫描8行、列
		{
			LEDDZ_COL_PORT=gled_col[i];//传送列选数据
			hc595_write_data(gled_row[i]);//传送行选数据
			delay_10us(100);//延时一段时间,等待显示稳定
			hc595_write_data(0x00);//消影	
		}								
	}		
}
/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net

实验名称:LED点阵实验(显示数字)
接线说明:	
实验现象:下载程序后,8*8LED点阵显示数字0
注意事项:LED点阵旁的J24黄色跳线帽短接到GND一端																				  
***************************************************************************************/
#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;

//定义74HC595控制管脚
sbit SRCLK=P3^6;	//移位寄存器时钟输入
sbit rCLK=P3^5;		//存储寄存器时钟输入
sbit SER=P3^4; 		//串行数据输入

#define LEDDZ_COL_PORT	P0	//点阵列控制端口

u8 gled_row[7][8]={{0x38,0x7C,0x7E,0x3F,0x1F,0x7E,0x7C,0x38},
					{0x00,0x18,0x3C,0x1E,0x1E,0x3C,0x18,0x00},
					{0x38,0x7C,0x7E,0x3F,0x1F,0x7E,0x7C,0x38},
					{0x00,0x18,0x3C,0x1E,0x1E,0x3C,0x18,0x00},
					{0x10,0x10,0x10,0x10,0x10,0x54,0x38,0x10},
					{0x60,0xF0,0x7C,0x7E,0xFF,0x6F,0x1E,0x0C},
					{0x60,0xF0,0x7C,0x7E,0xFF,0x6F,0x1E,0x0C},			
};//LED点阵显示数字0的行数据
u8 gled_col[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//LED点阵显示数字0的列数据

/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名         : hc595_write_data(u8 dat)
* 函数功能		   : 向74HC595写入一个字节的数据
* 输    入         : dat:数据
* 输    出         : 无
*******************************************************************************/
void hc595_write_data(u8 dat)
{
	u8 i=0;
	
	for(i=0;i<8;i++)//循环8次即可将一个字节写入寄存器中
	{
		SER=dat>>7;//优先传输一个字节中的高位
		dat<<=1;//将低位移动到高位
		SRCLK=0;
		delay_10us(1);
		SRCLK=1;
		delay_10us(1);//移位寄存器时钟上升沿将端口数据送入寄存器中	
	}
	rCLK=0;
	delay_10us(1);
	rCLK=1;//存储寄存器时钟上升沿将前面写入到寄存器的数据输出	
}


/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	u8 i=0, j=0, k=0;

	while(1)
	{			
		for (j = 0; j < 7; j ++)
		{
			k = 50;
			while (k --)
			{
				for(i=0;i<8;i++)//循环8次扫描8行、列
				{
					LEDDZ_COL_PORT=gled_col[i];//传送列选数据
					hc595_write_data(gled_row[j][i]);//传送行选数据
					delay_10us(100);//延时一段时间,等待显示稳定
					hc595_write_data(0x00);//消影	
				}
			}
			delay_10us(1000);			
		}
							
	}		
}

九、直流电机

/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net

实验名称:直流电机实验
接线说明:	
实验现象:下载程序后,直流电机旋转5S后停止
注意事项:将直流电机两根线分别连接到“步进电机模块”输出端子J47的5V和O1上。																				  
***************************************************************************************/
#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;

//定义直流电机控制管脚
sbit DC_Motor=P1^0;

#define DC_MOTOR_RUN_TIME	5000	//定义直流电机运行时间为5000ms


/*******************************************************************************
* 函 数 名       : delay_ms
* 函数功能		 : ms延时函数,ms=1时,大约延时1ms
* 输    入       : ms:ms延时时间
* 输    出    	 : 无
*******************************************************************************/
void delay_ms(u16 ms)
{
	u16 i,j;
	for(i=ms;i>0;i--)
		for(j=110;j>0;j--);
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	DC_Motor=1;//开启电机
	delay_ms(DC_MOTOR_RUN_TIME);
	DC_Motor=0;//关闭电机
	while(1)
	{			
								
	}		
}

十、步进电机

控制速度的方法:停止等待。

五条线:1条总电源,4条控制磁。

A->AB->B->BC->C->CD->D->DA 转子每次只走半步 45 度,所以 这也被称为半步驱动,与整步相比半步的旋转方式旋转起来更加的顺滑。

A->B->C->D 也能走,但是当休眠时间很短时就走不动了(该情况下8个分支的还能走)。

/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net

实验名称:步进电机实验
接线说明:	
实验现象:下载程序后,当按下KEY1键可调节电机旋转方向;当按下KEY2键,电机加速;
		  当按下KEY3键,电机减速
注意事项:将步进电机红色线对接到“步进电机模块”输出端子J47的5V上,其它相序依次接入。																				  
***************************************************************************************/
#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;

//定义ULN2003控制步进电机管脚
sbit IN1_A=P1^0;
sbit IN2_B=P1^1;
sbit IN3_C=P1^2;
sbit IN4_D=P1^3;

//定义独立按键控制脚
sbit KEY1=P3^1;
sbit KEY2=P3^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;

//使用宏定义独立按键按下的键值
#define KEY1_PRESS	1
#define KEY2_PRESS	2
#define KEY3_PRESS	3
#define KEY4_PRESS	4
#define KEY_UNPRESS	0

// 定义步进电机速度,值越小,速度越快
// 最小不能小于1
#define STEPMOTOR_MAXSPEED        1  
#define STEPMOTOR_MINSPEED        5  	


/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名       : delay_ms
* 函数功能		 : ms延时函数,ms=1时,大约延时1ms
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_ms(u16 ms)
{
	u16 i,j;
	for(i=ms;i>0;i--)
		for(j=110;j>0;j--);
}

/*******************************************************************************
* 函 数 名       : step_motor_28BYJ48_send_pulse
* 函数功能		 : 输出一个数据给ULN2003从而实现向步进电机发送一个脉冲
* 输    入       : step:指定步进序号,可选值0~7
				   dir:方向选择,1:顺时针,0:逆时针
* 输    出    	 : 无
*******************************************************************************/
void step_motor_28BYJ48_send_pulse(u8 step,u8 dir)
{
	u8 temp=step;
	
	if(dir==0)	//如果为逆时针旋转
		temp=7-step;//调换节拍信号
	switch(temp)//8个节拍控制:A->AB->B->BC->C->CD->D->DA
	{
		case 0: IN1_A=1;IN2_B=0;IN3_C=0;IN4_D=0;break;
		case 1: IN1_A=1;IN2_B=1;IN3_C=0;IN4_D=0;break;
		case 2: IN1_A=0;IN2_B=1;IN3_C=0;IN4_D=0;break;
		case 3: IN1_A=0;IN2_B=1;IN3_C=1;IN4_D=0;break;
		case 4: IN1_A=0;IN2_B=0;IN3_C=1;IN4_D=0;break;
		case 5: IN1_A=0;IN2_B=0;IN3_C=1;IN4_D=1;break;
		case 6: IN1_A=0;IN2_B=0;IN3_C=0;IN4_D=1;break;
		case 7: IN1_A=1;IN2_B=0;IN3_C=0;IN4_D=1;break;
		default: IN1_A=0;IN2_B=0;IN3_C=0;IN4_D=0;break;//停止相序	
	}			
}

/*******************************************************************************
* 函 数 名       : key_scan
* 函数功能		 : 检测独立按键是否按下,按下则返回对应键值
* 输    入       : mode=0:单次扫描按键
				   mode=1:连续扫描按键
* 输    出    	 : KEY1_PRESS:K1按下
				   KEY2_PRESS:K2按下
				   KEY3_PRESS:K3按下
				   KEY4_PRESS:K4按下
				   KEY_UNPRESS:未有按键按下
*******************************************************************************/
u8 key_scan(u8 mode)
{
	static u8 key=1;

	if(mode)key=1;//连续扫描按键
	if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))//任意按键按下
	{
		delay_10us(1000);//消抖
		key=0;
		if(KEY1==0)
			return KEY1_PRESS;
		else if(KEY2==0)
			return KEY2_PRESS;
		else if(KEY3==0)
			return KEY3_PRESS;
		else if(KEY4==0)
			return KEY4_PRESS;	
	}
	else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1)	//无按键按下
	{
		key=1;			
	}
	return KEY_UNPRESS;		
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	u8 key=0;
	u8 dir=0;//默认逆时针方向
	u8 speed=STEPMOTOR_MAXSPEED;//默认最大速度旋转
	u8 step=0;

	while(1)
	{			
		key=key_scan(0);
		if(key==KEY1_PRESS)//换向
		{
			dir=!dir;    
		}
		else if(key==KEY2_PRESS)//加速
		{
			if(speed>STEPMOTOR_MAXSPEED)
				speed-=1;			
		}
		else if(key==KEY3_PRESS)//减速
		{
			if(speed<STEPMOTOR_MINSPEED)
				speed+=1;			
		}
		step_motor_28BYJ48_send_pulse(step++,dir);
		if(step==8)step=0;		
		delay_ms(speed);						
	}		
}

十一、中断

有点像操作系统里面的0x80

11.1 外部中断(按键)

通常我们 都是使用基本的 2 个外部中断:INT0 和 INT1

INT0 对应的是 P3.2 口的附加功能;INT1 对应的是 P3.3 口的附加功能。

可由 IT0(TCON.0)选择其为低电平有 效还是下降沿有效。当 CPU 检测到 P3.2 引脚上出现有效的中断信号时,中断标 志 IE0(TCON.1)置 1,向 CPU 申请中断。

下降沿:被按下

这里有时红灯一闪一闪,原因:红外接收传感器与 K3 共用 P3.2 口。使用红外线遥控器同样可以开关。

/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net

实验名称:外部中断0实验
接线说明:	
实验现象:下载程序后,当按下K3键可控制D1指示灯亮灭
注意事项:将红外接收传感器取下,防止对P3.2口干扰																				  
***************************************************************************************/
#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;

//定义LED1管脚
sbit LED1=P2^0;

//定义独立按键K3控制脚
sbit KEY3=P3^2;


/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名       : exti0_init
* 函数功能		 : 外部中断0配置函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void exti0_init(void)
{
	IT0=1;//跳变沿触发方式(下降沿)
	EX0=1;//打开INT0的中断允许
	EA=1;//打开总中断
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	exti0_init();//外部中断0配置

	while(1)
	{			
							
	}		
}

void exti0() interrupt 0 //外部中断0中断函数
{
	delay_10us(1000);//消斗
	if(KEY3==0)//再次判断K3键是否按下
		LED1=!LED1;//LED1状态翻转					
}

11.2 定时器中断

工作方式图片
方式0
方式1
方式2
方式3

51 系列单片机一定有基本的 2 个定时器 (定时器 0 和定时器 1),但不全有 3 个中断,通常我们使 用的是基本的 2 个定时器:定时器 0/1。

常用的是方式1:总体上是TH0和TL0组成一个数字(各8位)做自增,当这个数字自增到溢出时发生一次中断。

/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net

实验名称:定时器0实验
接线说明:	
实验现象:下载程序后,D1指示灯间隔1s闪烁
注意事项:																				  
***************************************************************************************/
#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;

//定义LED1管脚
sbit LED1=P2^0;



/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名       : time0_init
* 函数功能		 : 定时器0中断配置函数,通过设置TH和TL即可确定定时时间
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void time0_init(void)
{
	TMOD|=0X01;//选择为定时器0模式,工作方式1
	TH0=0XFC;	//给定时器赋初值,定时1ms
	TL0=0X18;	
	ET0=1;//打开定时器0中断允许
	EA=1;//打开总中断
	TR0=1;//打开定时器		
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	time0_init();//定时器0中断配置

	while(1)
	{			
							
	}		
}

void time0() interrupt 1 //定时器0中断函数
{
	static u16 i;//定义静态变量i
	TH0=0XFC;	//给定时器赋初值,定时1ms
	TL0=0X18;
	i++;
	if(i==1000)
	{
		i=0;
		LED1=!LED1;	
	}						
}

十二、串口通信

实验软件的波特率要和程序里写的波特率一样。

RS232 的通信协议比较简单,通常遵循 96-N-8-1 格式。 “96”表示的是通信波特率为 9600。串口通信中通常使用的是异步串口通 信,即没有时钟线,所以两个设备要通信,必须要保持一致的波特率。

如果使用黄色跳线帽将 P5 端子的 1、2 短接,3、4 短接,那么 CH340 串口与 单片机串口是连接一起的,此时即可实现程序的下载或串口通信。

/**************************************************************************************
深圳市普中科技有限公司(PRECHIN 普中)
技术支持:www.prechin.net

实验名称:串口通信实验
接线说明:	
实验现象:下载程序后,当串口助手发送数据给单片机,单片机原封不动转发给串口助手显示
注意事项:使用黄色跳线帽将CH340旁的P5端子的UTX和P30短接,URX和P31短接,出厂默认已短接好																				  
***************************************************************************************/
#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;


/*******************************************************************************
* 函 数 名       : uart_init
* 函数功能		 : 串口通信中断配置函数,通过设置TH和TL即可确定定时时间
* 输    入       : baud:波特率对应的TH、TL装载值
* 输    出    	 : 无
*******************************************************************************/
void uart_init(u8 baud)
{
	TMOD|=0X20;	//设置计数器工作方式2
	SCON=0X50;	//设置为工作方式1
	PCON=0X80;	//波特率加倍
	TH1=baud;	//计数器初始值设置	   
	TL1=baud;
	ES=1;		//打开接收中断
	EA=1;		//打开总中断
	TR1=1;		//打开计数器		
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	uart_init(0XFA);//波特率为9600

	while(1)
	{			
							
	}		
}

void uart() interrupt 4 //串口通信中断函数
{
	u16 rec_data;

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

传入再传出。尝试了下加法,效果步理想。

十三、I2C-EEPROM 实验

只能说这个实验只能勉强理解在干啥。

13.1 项目总览

从这里开始不再是一个光.c文件了。

照着教程配了下文件。下载时记得要换文件路径了。

程序由以下几个功能实现:

功能名称功能
key按键检测
smg数码管显示
iicI2C 读写字节
24c02AT24C02 读写字节

13.2 通信协议

模拟I2C时序,实现与 AT24C02(EEPROM)之间的双向通信。

13.2.1 I2C

SCL时钟线 SDA数据线

一个 I2C 总线只使用两条总线线路,一条双向串行数据线(SDA),一 条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。

总线通过上拉电阻接到电源。当 I2C 设备空闲时,会输出高阻态,而 当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。

应答:低电平脉冲

非应答:高电平脉冲

13.2.2 AT24C02

根据iic协议实现传输

13.3 小结

模拟的iic协议。大概能理解意思,没太懂这个实验的细节。

十四、DS18B20 温度传感器实验

用传感器采集数据后显示出来,重点在于处理采集到的数据。

传输数据等操作时必须要有拉低DQ后DQ=1的操作。按照硬件的操作要求来。

十五、小结

之后的实验似乎都是连接外设,根据外设的硬件规范编写相应的连接函数再操作,这里就不再写了。

我觉得单片机和平时接触到的不同点在于:它是和硬件一同完成功能的。硬件提供接口,程序捕捉或改变接口的电气性质完成操作。

对电脑是怎样跑起来的多了点儿理解。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值