51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)

写博客的主要目的还是自己需要考试了,写在这里总结一番,如果给大家带来了帮助。鄙人不甚欢喜,如果有错误,欢迎大家指出

内容概要

  • 主控芯片
    • 8*8点阵
      • 串口通信

主控芯片

51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)_第1张图片

8*8点阵

原理图:
51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)_第2张图片
51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)_第3张图片(注:在51清翔单片机上面,这8个引脚是引出来,所以88使用的是这个原理图里面的1-6个引脚)
(注:清翔的点阵屏把需要使用的74HC595放到了点阵屏模块里面)
实物:
51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)_第4张图片51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)_第5张图片74HC595
因为点阵里面有8
8个LED灯,所以直接用串口去一个一个控制是不现实的,所以我们需要借助到595芯片。这一种芯片是一种串入并出的芯片,在电子显示屏里面被广泛的应用。其实质是串行输入/输出或者并行输出移位寄存器
芯片手册
51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)_第6张图片使用方法

SCLK和RCLK全部拉低到0
将需要输入的数据按照2进制压入一个
拉高SCLK
拉低SCLK

模块化代码

/*pbdata.h*/
#ifndef __PBDATA_H__
#define __PBDATA_H__
#define uchar unsigned  char
#define uint unsigned int

#include 
#include 
#include "Matrix.h"

/*8*8点阵*/
sbit DIO = P3^4;  //串行数据口
sbit S_CLK = P3^5;//移位寄存器时钟
sbit R_CLK = P3^6;//输出锁存器时钟

#endif
/*Matrix.h*/
#ifndef __MATRIX_H__
#define __MATRIX_H__


void Send_Byte(unsigned char dat);
void Display_DZ(uchar num);

#endif
/*Matrix.c*/
#include"pbdata.h"

/*点阵字形码*/
/*要显示的字符*/
unsigned char code tabel[2][8]={
0xE0,0xEE,0x01,0x6D,0x01,0x6D,0x01,0xEF,//"电"字符
0xE7,0xF7,0xF7,0xF7,0x80,0xF7,0xFB,0xC3//“子”字符
};

/*595发送一字节*/
void Send_Byte(unsigned char dat)
{
	unsigned char i; //循环次数变量
	S_CLK = 0;//拉低移位寄存器时钟
	R_CLK = 0;//拉低输出锁存器时钟
	for(i=0; i<8; i++) //循环8次
	{
		if(dat & 0x01)//发送1
			DIO = 1;
		else	  //发送0
			DIO = 0;
		dat >>= 1;//数据右移
		S_CLK = 1;//拉高移位寄存器时钟,数据移位
		S_CLK = 0;//拉低移位寄存器时钟
	}	
}

/*num表示需要输出的字符数字数量*/
void Display_DZ(uchar num)
{
	unsigned char j, k, ROW;//j发送8列和8行字形码,k字符数量,ROW行值
	unsigned int z;	//动态扫描延时变量
	while(1)
	{
		for(k=0; k<num; k++)//k 需要显示的字符数量
		{
			for(z=0; z<1000; z++)//z刷新次数
			{
				ROW = 0x80;//行选初值
				for(j=0; j<8; j++) //循环8次发送行和列值
				{
					Send_Byte(tabel[k][j]);//发送列选值
					Send_Byte(ROW);	//发送行选值
					R_CLK = 1; //拉高输出锁存器,把移位寄存器中数据输出
					R_CLK = 0; //拉低输出锁存器
					ROW = _cror_(ROW, 1);//右移,选择下一行	
				}
			}
		}
	}
}
/*main.c*/
#include "pbdata.h"

void main()
{
	while(1)
	{
		Display_DZ(2);
	}
}

(注:字符字形码根据自己的需要修改,有一个小软件可以直接求出来你需要显示的字形码的字符,可以私聊发)
(注:在更改了显示字符的时候,要注意改tabel喝Display_DZ两个的参数)

串口通信

如果不想看原理 可以直接拉到最下面去看模块化代码,简单直接粗暴,更省时省心省力
波特率
要学习串口通信,就一定要知道波特率,波特率就是每秒钟传输二进制代码的位数,单位是:位/秒(bps)
用一个简单的例子来讲解波特率,比如每秒钟传输240个字符,而每个字符的格式包含10位(1个起始位、1个停止位、8个数据位),这时候的比特率就是10位*240个/秒 = 2400 bsp
波特率的计算
51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)_第7张图片
51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)_第8张图片SMOD没配置的话默认为0
fosc是外部晶振 我们使用的是11.0592MHZ晶振
寄存器配置
因为通信需要中断,示意图在串行口工作之前必须要对相关寄存器进行配置,设定其工作模式。

设置T1工作方式 编辑TMOD寄存器
计算T1初值 装载TH1 TL1
启动T1 编辑TCON中的R1位
确定串行口控制 编辑SCON寄存器
如果需要串行口在中断下工作 在中断设置编程IE寄存器

数据手册
51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)_第9张图片51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)_第10张图片51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)_第11张图片51单片机学习总结(三)8*8点阵屏,串口通信(内含模块代码)_第12张图片模块化代码

/*Uart.h*/
#ifndef __Uart_H__
#define __Uart_H__

void UartAction(unsigned char *buf, unsigned char len);
void ConfigUART(unsigned int baud);
void UartWrite(unsigned char *buf, unsigned char len);
unsigned char UartRead(unsigned char *buf, unsigned char len);
void UartRxMonitor(unsigned char ms);
void UartDriver();

#endif
/*Uart.c*/
#include 
#include 
#include 
//存储数据到bufRxd[]数组里面,buf[]是另外一个存储谁都可以调用
//加上extern之后,不需要声明包含这个文件
#define uchar unsigned char 
#define uint unsigned int

bit flagFrame = 0; //帧接收完成标志,即接收到一帧新数据
bit flagTxd = 0; //单字节发送完成标志,用来替代TXD 中断标志位
unsigned char cntRxd = 0; //接收字节计数器
unsigned char pdata bufRxd[64]; //接收字节缓冲区 ,存储到RAM中

// 串口动作函数,用来添加自己需要的额外函数
void UartAction(unsigned char *buf, unsigned char len);

/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud)
{
	EA = 1;			//打开总中断
	ES = 1; 		//打开串口中断
	SM0 = 0;SM1 = 1;	//串口工作方式1,8位UART波特率可变
	REN = 1;		//串口允许接收
	TR1 = 1;		//启动定时器1
	TMOD |= 0x20;		//定时器1,工作模式2 8位自动重装
	TH1=256-(11059200/12/32)/baud;
	TL1=TH1;
}
/* 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */
void UartWrite(unsigned char *buf, unsigned char len)
{
	while (len--) //循环发送所有字节
	{
		flagTxd = 0; //清零发送标志
		SBUF = *buf++; //发送一个字节数据,发送一个字节,然后指针后移
		while (!flagTxd); //等待该字节发送完成
	}
}
/*串口读取数据函数*/
unsigned char UartRead(unsigned char *buf, unsigned char len)
{
	unsigned char i;
	if (len > cntRxd) //指定读取长度大于实际接收到的数据长度时,
	{ //读取长度设置为实际接收到的数据长度
		len = cntRxd;
	}
	for (i=0; i<len; i++) //拷贝接收到的数据到接收指针上
	{
		*buf++ = bufRxd[i];//把发送到bufRxd上的数据存到buf上
	}
	cntRxd = 0; //接收计数器清零
	return len; //返回实际读取长度
}
/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔,一般1ms即可*/
void UartRxMonitor(unsigned char ms)
{
	static unsigned char cntbkp = 0;
	static unsigned char idletmr = 0;
	if (cntRxd > 0) //接收计数器大于零时,监控总线空闲时间
		{
		if (cntbkp != cntRxd) //接收计数器改变,即刚接收到数据时,清零空闲计时
		{
			cntbkp = cntRxd;//改变接收计数器
			idletmr = 0; //清0空闲计时
		}
		else //接收计数器未改变,即总线空闲时,累积空闲时间,判断是否接受完毕
		{
			if (idletmr < 30) //空闲计时小于30ms 时,持续累加
			{
				idletmr += ms;
				if (idletmr >= 30) //空闲时间达到30ms 时,即判定为一帧接收完毕
				{
					flagFrame = 1; //设置帧接收完成标志
				}
			}
		}
	}
		else
		{
			cntbkp = 0;
		}
}
/* 串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用 */
void UartDriver()
{
	unsigned char len;
	unsigned char pdata buf[40];
	if (flagFrame) //有命令到达时,读取处理该命令
	{
		flagFrame = 0;//改变状态为忙碌
		len = UartRead(buf, sizeof(buf)); //将接收到的命令读取到缓冲区中,并且放入buf中
		UartAction(buf, len); //传递数据帧,调用动作执行函数
	}
}
/* 串口中断服务函数 */
void InterruptUART() interrupt 4
{
	if (RI) //接收到新字节
	{
		RI = 0; //清零接收中断标志位
		if (cntRxd < sizeof(bufRxd)) //接收缓冲区尚未用完时,
		{ //保存接收字节,并递增计数器
			bufRxd[cntRxd++] = SBUF;
		}
	}
	if (TI) //字节发送完毕
	{
		TI = 0; //清零发送中断标志位
		flagTxd = 1; //设置字节发送完成标志
	}
}

你可能感兴趣的:(单片机学习)