Autoleaders控制组——有关矩阵键盘、定时器、串口通信

一、模块化编程

 

1、把各个模块的代码放在.c文件中(注意为.c文件)

2、在.h文件里提供外部可调用的函数的声明(注意为.h文件)

3、其他.c文件想使用其中代码时,只需要#include"xxx.h"文件即可(#include< >与#include" "的区别在于前者是在目录中查找,而后者是在自己的程序的文件查找,因此需要提前把所应用的函数放进本文件夹中,否则会找不到而出现错误

4、define语句:#define PI 3.14的意思为将PI代替为3.14;#define ABC的意思为定义ABC

5、.h程序的格式:(外部可调用的函数放在.h文件内)

#ifndef__xxx_H__   //xxx为文件名

#define__xxx_H__

void xxx();  //函数声明

#endif

二、LCD1602调试工具

1、该单片机的液晶显示屏。会与数码管和LED所用的管脚冲突,因此使用该工具会导致数码管乱码,LED的前三个灯无法使用

2、(提供的LCD1602代码属于模块化代码)

LCD_Init();  //初始化是必须的

LCD_ShowChar(, ,); //显示一个字符

LCD_ShowSrting(, ,); //显示字符串

LCD_ShowNum(, , ,); //显示十进制数字

LCD_ShowSignedNum(, , ,); //显示带有符号的十进制数字

LCD_ShowHexNum(, , ,); //显示十六进制数字

LCD_ShowBinNum(, , ,); //显示二进制

(注意每个函数的变量查看模块里的注释)

三、矩阵键盘

1、扫描:矩阵键盘为输入扫描:过程大致为读取第1位(列)——第2位(列)——......——迅速循环这个过程。(可以逐行扫描也可以逐列扫描,但由于线路问题,所以首选逐列扫描)

2、示例 

    P1=0xFF;
    P1_3=0;//这两步相当于将矩阵清零后,选择第一列
    if(P1_7==0){Delay1ms(20);while(P1_7==0);Delay1ms(20);keynum=1;}
    if(P1_6==0){Delay1ms(20);while(P1_6==0);Delay1ms(20);keynum=5;}
    if(P1_5==0){Delay1ms(20);while(P1_5==0);Delay1ms(20);keynum=9;}
    if(P1_4==0){Delay1ms(20);while(P1_4==0);Delay1ms(20);keynum=13;}

(1)第一行将P1矩阵清零;第二行P1_3=0表示选择了图中P13这一列。

(2)第三行P1_7=0表示选择了图中P17这一行,结合第一列,也就是图中S1,后面将1赋给了kuynum。

(3)剩下几行同理,按下S5,S9,S13,都将相应的值赋给了keynum。

(将其包装为模块keyboard,方便以后直接运用它)

3、

#include <REGX52.H>
#include "Delay1ms.h"
#include "LCD1602.h"
#include "keyboard.h"

unsigned char keynum;

void main()
{
	char a[16]="input a number";
	LCD_Init();
	LCD_ShowString(1,1,a);
	while(1)
	{
		keynum=keyboard();//将keyboard这个函数的返回值赋予keynum
		if(keynum)//即为keynum!=0
		{
			LCD_ShowNum(2,1,keynum,2);//末尾为输入两位数,若不足两位,自动补为0
		}
	}
}

(1)我们这里运用了四个文件,分别是系统文件、Delay1ms文件(延迟)、LCD1602文件(液晶显示屏)、keyboard文件(矩阵键盘)

(2)LCD_Init();为初始化LCD函数,方可运用LCD1602

(3)这里运用了LCD函数中的LCD_Showstring()模块。LCD_Showstring(1,1,a),表示在液晶显示屏的第一行,第一位数开始显示字符a,前面定义了字符a为input a number。

(4)while函数内将keyboard的值赋给了前面定义的keynum,紧接着if语句,if(keynum)表示只要kuynum有数值,不等于0,就进入if函数,然后运用LCD_ShowNum然后根据keynum的值来显示数值,(2,1,keynum,2)的意思是液晶屏第二行第一格开始显示keynum,占两格。

四、定时器 

1、属于单片机的内部资源,其电路的连接和运转均在单片机内部完成 

2、作用:(1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作

                (2)代替长时间的Delay,提高CPU的运行效率和处理速度(使用Delay短暂的时间时,是无法使用单片机的其他功能的)

3、个数:该单片机有3个定时器(T1、T2、T3),T0与T1与传统的51单片机兼容,T2是此型号单片机增加的资源

4、STC89C52的T0和T1均有四个工作模式

模式0:13位定时器/计数器

模式1:16位定时器/计数器

模式2:8位自动重装模式

模式3:两个8位计数器

5、模式——组成:时钟&计数&中断

(1)时钟给计数器一个脉冲,使其加一

(2)计数器最大内存为65535,溢出+1会变回0,进而申请中断

(3)系统时钟:SYSclk,即晶振周期,本开发板为12MHZ,时钟会将12MHZ进行12分频变为1MHZ(1微秒)

(4)C/T:当给1(高电频),为C——计数器;当给0(低电频),为T——定时器。

(5)中断请求:总是先处理优先级别高的

(6)中断嵌套:正在处理一个中断请求时,发生了另一个级别比它还高的中断源请求,CPU你能够暂停转而去处理优先级更高的中断请求,处理完之后再继续处理原来的。

(7)中断资源:有8个中断源,有4个中断优先级

6、寄存器TMOD各位功能:

TOMD地址:89H     复位值:00H

 (1)M1,M0控制:(0,0)13位定时器;(0,1)16位定时器;

                                (1,0)8位定时器;(1,1)定时器/计数器无效(即为停止)

 (2)GATE(控制端):

 (注意电路中的或、与逻辑语句)

(3)不可位寻址:只能整体赋值(TMOD)

         可位寻址:可给其中的每一位单独赋值(TCON)

7、STC中的定时器计算器配置

(1)频率12.000MHZ

(2)定时长度1毫秒

(3)定时器0

(4)定时器模式16位

(5)定时器时钟12T

8、设置定时器:

void Timer0Init()
{
	/*TMOD=0x01; 0000 0001->使得定时器M0口为1,其他为0。此时定时器0的M1为0、M0为1,C/T为C(定时器),因此为16位定时器;
	GATE端为0,由于电路结构可得到单纯由TR0控制输出*/
	
	TMOD=TMOD&0xF0;//把TMOD低四位清零,高四位不变
	TMOD=TMOD|0x01;//把TMOD的最低位变1,高四位不变
	/*当TMOD为1010 0001,->1010 0000,->1010 0001*/
	TF0=0;//控制定时器工作,确保其初始值为0,让其工作
	TR0=1; //当TR0=1时,才允许T0开始计数;为0会禁止
		   //(TF和TR0为TCON的一部分,其为可寻位址,因此可以给其中每一位单独赋值)
	TH0=0xFC;/*64535/256*/
	TL0=0x18;/*64535%256*///用TH0和TL0分别存储64535,前者为高位,后者为低位
	/*使用64535使得时钟每记一次即增加到达65535,时间为1000微秒,即为1毫秒 */
	ET0=1;
	EA=1;
	PT0=0;//这三行是为了打通中断系统的通路
}

 (注意当函数遇到中断时,会跳转到中断函数内。中断函数的特征:函数名后有相应的中断号:interrupt x)

void Timer0_Routine() interrupt 1  //中断服务函数
{
	unsigned int T0count;
	TH0=0xFC;
	TL0=0x18;//每次中断完后,TH0和TR0都会为溢出为0,因此需要重新赋值
	T0count++;
	if(T0count>=1000)  //一次为1毫秒,一千次为1秒
	{ 
		T0count=0;
		P2_0=~P2_0;
	}
	 
}

(这里的中断函数内,P20LED灯会以一秒为周期闪烁)

9、定时器的其他运用

(1)时钟:

#include <REGX52.H>
#include "Delay1ms.h"
#include "Time0.h"
#include "LCD1602.h"
unsigned char sec,min,hour;
void main()
{
	LCD_Init();//这个也是初始化!!!
	LCD_ShowString(1,1,"CLOCK:");
	LCD_ShowString(2,3,":");
	LCD_ShowString(2,6,":");
	Timer0Init();//注意要初始化.h文件的声明!!!
	while(1)
	{
		
		LCD_ShowNum(2,1,hour,2);
		LCD_ShowNum(2,4,min,2);
		LCD_ShowNum(2,7,sec,2);
	}
}

void Timer0_Routine() interrupt 1  //中断服务函数
{
	unsigned int T0count;
	TH0=0xFC;
	TL0=0x18;//每次中断完后,TH0和TR0都会为溢出为0,因此需要重新赋值
	T0count++;
	if(T0count>=1000)  //一次为1毫秒,一千次为1秒
	{ 
		T0count=0;
		sec++;
		if(sec>=60)
		{
			sec=0;
			min++;
			if(min>=60)
			{
				min=0;
				hour++;
			}
		}
	}
	 
}

(需要注意的是运用模块时,要将程序放进该程序文件夹中,并且添加到该程序中。)

(2)定时器控制LED灯流动:

#include <REGX52.H>
#include "Time0.h"
#include "keyboard_2.h"
#include <INTRINS.H>//系统带的函数
unsigned char keynum;
unsigned char LEDMode;
void main()
{
	P2=0xFE;
	Timer0Init();//应用闹钟,然后跳转到下面一个函数void Timer0_Routine() interrupt 1中
	while(1)
	{
		keynum=key();
		if(keynum)
		{
			if(keynum==1)
			{
				LEDMode++;//按一次P3_1使得LEDMode改变,一开始为0,按一下后为1,再按一下后为2,2经过if语句变为0
				if(LEDMode>=2)LEDMode=0;//使得Mode0101变化
			}
		}
	}
}

void Timer0_Routine() interrupt 1  //中断服务函数
{
	unsigned int T0count;
	TH0=0xFC;
	TL0=0x18;//每次中断完后,TH0和TR0都会为溢出为0,因此需要重新赋值
	T0count++;
	if(T0count>=500)  //一次为1毫秒,一千次为1秒
	{ 
		T0count=0;
		if(LEDMode==0)
			P2=_crol_(P2,1);
		if(LEDMode==1)
			P2=_cror_(P2,1);
	}
	 
}

·注意到的是该程序的头文件多了#include <INTRINS.H>文件,该文件是程序自带的

·我们运用到了P2=_crol_(P2,1)和P2=_cror_(P2,1),_crol_表示向左移动一格,_cror_表示向右移动一格。与<<和>>不一样,<<和>>移动到最高位后会溢出,而_crol_和_crol_到达最高位后会跳到最低位,也就是说不需要判断重新赋值。P2=_crol_(P2,1)表示将P2这列数整体向左移动1格

五、串口通信

1、串口通信的介绍:

(1)应用广泛的通讯接口,实现两个设备互相通信,成本低,线路简单。

(2)单片机与单片机、单片机与电脑,与各种模块互相通行

(3)51单片机内部自带UART

2、简单双向串口通信有两根通信线:发送端TXD和接收端RXD(其中TXD与RXD要交叉连接)

(其中VCC为供电接口,如有电源可不连接;GND为对地接口) 

3、电平标准:(数据1和数据0的表达方式)

(1)TTL电平:+5V表示1,0V表示0

(2)RS232电平:-3~-15V表示1,+3~+15V表示0

/*(1)和(2)为对地电压*/

(3)RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号即两线电压)

4、术语:

(1)全双工:双方可以在同一时刻互相传输数据(两根线)

(2)半双工:通信双方可以互相传输数据,但必须分时复用一根数据线

(3)单工:不能反向运输

(4)异步:双方各自约定通信速率

(5)同步:靠一根时钟线来约定通信速率

(6)总线:连接各个设备的数据传输路线

5、参数:

(1)波特率:串口通信的速率(发送与接接收的间隔时间)

(2)比特率:传送位数

(3)检验位(9位数据格式才有):用于数据验位(奇偶校验)

实际上是检查数据中1的个数:如采用奇校验:0000 0011 1(这个1是我们人为添加上去的,和系统约定好的)->0000 0011 1检验1的个数为奇数,为正确;若为偶数,则系统重新发送,这样有利于传输的数据是正确的。

(4)串口助手的配置

选择:12.000MHZ,4800波特率,串口1,8位数据,定时器1(8位自动重载),定时器时钟12T,选择加倍

6、控制寄存器

#include <REGX52.H>

void UartInit(void)		//4800bps@12.000MHz
{
	//串口配置
	PCON |= 0x80;		//使能波特率倍速位SMOD
	SCON = 0x50;		//8位数据,可变波特率
	//定时器配置
	TMOD &= 0x0F;		//清除定时器1模式位
	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
	TL1 = 0xF3;		//设定定时初值
	TH1 = 0xF4;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
}

void UART_SendByte(unsigned char Byte)//该函数是单片机发送端向接收端发送数据,能显示出来
{
	SBUF=Byte;//我们输入Byte给到SBUF即可
	while(TI==0);//检测是否完成,
	TI=0;//可以使函数完整运行
}

(1)SCON中的SM0,SM1确定串口工作方式:(0,1)为方式1,是常用的工作方式

(2)SCON中的REN用于允许或者禁止接收控制位(REN=1->允许)

(3)TB8;RB8

(4)TI:用来复位,完成一段指令后必须用其来复位为0;RI:同TI

7、中断跳转位函数名可以自己取,但需要在末尾加上相应的中断号“interrupt +数字”

8、发送中断与接收中断:

 9、波特率计算:

(1)12MHZ晶振在12T环境下每1微秒记1次数,记了13个数,即每隔13微秒溢出一次

(2)定时器溢出率=1/13微秒≈0.07692MHZ(微秒/次)

(3)波特率:0.0769/16≈0.00480769MHZ=4807.69HZ

(4)误差:7.69/4800*100%=0.16%

10、数据显示模式

(1)HEX模式(十六进制模式/二进制模式):以原始数据的形式显示

(2)文本模式:以原始数据编码后的形式显示,如0x41显示为'A'

六、LED点阵屏

1、介绍:由若干个独立的LED组成,以矩阵排列

分类:(1)颜色:单色、双色、全彩(2)像素:8*8,16*16(可拼接)

电路:与数码管相似,也有共阴极与共阳极。LED点阵屏需要进行逐行或者逐列扫描才能使所有LED同时显示。

2、74HC595:

3、特殊功能寄存器(sfr)(给相应名称变量地址) 

sfr P0= 0x80;声明P0口寄存器,物理地址为0x80

特殊位声明(sbit)

sbit P0_1=0x80或sbit P0_1=P0^1;声明P0寄存器第一位

4、unsigned char code Animation[]={}

这是个存放LED图像的代码数组,由于内存大,应放在code指代的flash空间内,不占主要内存。(但是注意放在flash之后,在主函数内无法更改,只能读取

5、LED点阵屏的函数模块:

#include <REGX52.H>
#include "Delay1ms.h"

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

#define MATRIX_LED_PORT 	P0//用其他来代替P0

void _74HC595_WriteByte(unsigned char Byte)
{
	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,Date)
{
	_74HC595_WriteByte(Date);//选择列显示的数据,高位在上,1为亮,0为灭(共阳极连接)
	MATRIX_LED_PORT=~(0x80>>Column);//选定列:0~7
	Delay1ms(1);//消影
	MATRIX_LED_PORT=0xFF;//清零
}

void MatrixLED_Init()
{
	SCK=0;
	RCK=0;//初始定义
}


/*void main()
{
	SCK=0;
	RCK=0;//初始定义
	while(1)
	{
		MatrixLED_ShowColumn(0,0xF0);
		MatrixLED_ShowColumn(1,0xF0);
		MatrixLED_ShowColumn(2,0xF0);
		MatrixLED_ShowColumn(3,0xF0);
		MatrixLED_ShowColumn(4,0xF0);
		MatrixLED_ShowColumn(5,0xF0);
		MatrixLED_ShowColumn(6,0xF0);
		MatrixLED_ShowColumn(7,0xF0);		
	}
}*/

 LED点阵屏显示函数展示

#include <REGX52.H>
#include "Delay1ms.h"
#include "MATRIX_LED_PORT.h"
sbit RCK=P3^5;//RCLK
sbit SCK=P3^6;//SRCLK
sbit SER=P3^4;//SER

unsigned char code Animation[]={/*所要显示的图像的代码*/
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//填补前面的空隙
	0x81,0x81,0xFF,0x81,0x81,0x00,0x70,0x88,
	0x84,0x82,0x41,0x21,0x41,0x82,0x84,0x88,
	0x70,0x00,0x80,0x40,0x20,0x1F,0x20,0x40,
	0x80,0x00,0x00,0x00,0xFD,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//填补后面的空隙
};

void main()
{
	unsigned char i,offset,count;
	MatrixLED_Init();
	while(1)
	{
		for(i=0;i<8;i++)
		{
			MatrixLED_ShowColumn(i,Animation[i+offset]);//i+offset使LED流动
		}
		count++;//记录扫描的次数
		if(count>10)
		{
			count=0;
			offset++;//流动到下一位
			if(offset>40)//防止尽头处出现乱码
			{
				offset=0;
			}
		}
	}
}
/*MatrixLED_ShowColumn(0,Animation[0]);
		MatrixLED_ShowColumn(1,Animation[1]);
		MatrixLED_ShowColumn(2,Animation[2]);
		MatrixLED_ShowColumn(3,Animation[3]);
		MatrixLED_ShowColumn(4,Animation[4]);
		MatrixLED_ShowColumn(5,Animation[5]);
		MatrixLED_ShowColumn(6,Animation[6]);
		MatrixLED_ShowColumn(7,Animation[7]);*/

  其中获取图像代码数列的方式为使用取模软件:

(1)模拟动画:放大格点到一定程度

(2)基本操作:新建图像,选择合适的点阵大小

(3)取模方式:选择C51

(4)设计好图案后,点击点阵生成区,即可复制代码,粘贴至数列中

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值