写博客的主要目的还是自己需要考试了,写在这里总结一番,如果给大家带来了帮助。鄙人不甚欢喜,如果有错误,欢迎大家指出
原理图:
(注:在51清翔单片机上面,这8个引脚是引出来,所以88使用的是这个原理图里面的1-6个引脚)
(注:清翔的点阵屏把需要使用的74HC595放到了点阵屏模块里面)
实物:
74HC595
因为点阵里面有88个LED灯,所以直接用串口去一个一个控制是不现实的,所以我们需要借助到595芯片。这一种芯片是一种串入并出的芯片,在电子显示屏里面被广泛的应用。其实质是串行输入/输出或者并行输出移位寄存器
芯片手册
使用方法
模块化代码
/*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
波特率的计算
SMOD没配置的话默认为0
fosc是外部晶振 我们使用的是11.0592MHZ晶振
寄存器配置
因为通信需要中断,示意图在串行口工作之前必须要对相关寄存器进行配置,设定其工作模式。
/*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; //设置字节发送完成标志
}
}