摘要:目前,所有型号串口的输入是输出是。串口全双工通信是没有时钟脉冲的,只能依靠晶振脉冲定时器的溢出脉冲。中断中读取,清标志,然后返回给计算机,等待发送完毕防重叠最少时间次位定时器时间。实现烧录程序的目的。
多位数据同时传输
通讯介质通常为TTL,差分(低压差分芯片)
例如:LCO1602,ADC0804,LVDS(液晶显示)等
多位数据排队传输,任意IO口都可以做数据收发
通信介质通常为TTL,差分(485),无线电
74HC595(单工),IIC(半双工),SPI
单线归零、1- Wire 、 CAN 总线、无线电、UART (含 DMX512 、 modbus )。
UART 是单片机的独立模块。我们设置好模块的参数,需要发送什么内容,扔给串口模块就行。 CPU 不需要按位读写。该模块是指定的管脚输入输出。目前, STC 所有型号串口1 的输入是 RxD1=P3.0, , 输出是 TxD1=P3.1 。
STC15 开发板使用 STC15W4K16S4 芯片,串口有4个,其中串口3的输入是 RxD3= P0.0, , 输出是 TxD3= P0.1 。与矩阵键盘共用了两个 IO
CPU 往 SBUF 中写入一个 byte , CPU 可以跑去执行其他函数。如果发送完成,串口模块向 CPU 申请中断(T1);
串口收发一位数据,依靠严格的时间来保证收发同步
如果串口模块接收完一个字节,也向 CPU 申请中断( RI ),CPU 可以从 SBUF 中读取数据。
**1.位采样脉冲:**接收器把每个 bit 的时间平均等份,对线路电平进行采样,确定接收到的是高电平还是低电平,才能进行下一位数据的采样。 STC89 是 16 等份判断7、8 、9(三选二)。STC15W 和 STC8 系列是4等份(四选三,官方资料写错成 16 了)
2.波特率:: 是指1秒钟的时间内,串口通信线路上面,发送的数据位数, , 简单理解成1秒钟内电平跳变多少次
常用的波特率有 9600 等, STC 下载软件里面可以选择的就有很多种波特率。我们后面要学的 DMX512 就是 250000bps .
**波特率的本质,是设置信号时间点。**到点就按时发送或者接收一位。串口全双工通信是没有时钟脉冲的,只能依靠晶振脉冲、定时器的溢出脉冲。
==3.波特率哪里来:==波特率来自定时器的溢出,独立波特率发生器,以及系统时钟分频
波特率是 9600 ,每位采样4次。就需要定时器2每秒钟溢出 9600*4 次 =38400
定时器2溢出需要的脉冲数是:24000000 ÷ 38400=625. 那么,定时器2的预装初值就是:65536-625=64911=0xFD8F
void Uart1_Init(){ SM0 = 0; SM1 = 1; REN = 1; //上面三条语句就等于操作SCON |= 0x50; PCON &= 0x3f; AUXR |= 0x01; AUXR |= 0x14; T2H = 0xfd; T2L = 0x8f; ES = 1;}
在中断里面我们干什么,进中断第一件事就是先把接收标志,发送标志给软件清零,然后再做一系列操作
void Uart1_Routine() interrupt 4{ if (RI) { RI = 0;//先把接收标志给清零 Uart1_Data = SBUF; } if (TI) { TI = 0;//先把发送标志给清零 }}
监控串口通信内容,如果在 9600 波特率下,连续收到 10 个字节都是 0x7f, 那么让单片机软复位,去支持 ISP 监控区域代码。实现烧录程序的目的。单片机不断电就可下载程序,方便项目调试
上面我们故意用最低波特率与最高波特率都是1200,小于9600,我就点了下载,(板子是上电的)没有用板子的开关复位,就是通过纯软件复位,等了几秒没有反应,说明我们用9600下载的方式是不支持1200下载的
9600很慢的(哈哈)下载了
我们发现只要最低波特率到9600就可以软复位了,越高会下载越快
void Uart1_Routine() interrupt 4{ //记录接收命令流变量 static char Uart1_ser_n = 0; if (RI) { RI = 0;//先把接收标志给清零 Uart1_Data = SBUF; if (SBUF == 0x7f) //9600波特率 { //接收命令为0x7f时就++ Uart1_ser_n++; if(Uart1_ser_n > 10)//大于10基本就是确定是下载命令 { Uart1_ser_n = 0; //然后执行软复位 IAP_CONTR |= 0xe0; } } } if (TI) { TI = 0;//先把发送标志给清零 }}
为什么一直是0xFF,眼看也不是1啊是不是 ,我们用逻辑分析仪来抓取看看
完美,为了让你直观的看到美,我采集一下给你们看看
我们给他一个标志位,前面一个字节发送完成后,标志位修改,然后发第二个字节,以此类推
//串口发送底层驱动的函数void Uart1_Up_Data_Drive(){ //串口1标志为1才能发送字节, //可以让数据有效的发送 if(Uart1_Flag) { Uart1_Flag = 0; SBUF = 1; }}//串口1中断void Uart1_Routine() interrupt 4{ //记录接收命令流变量 static char Uart1_ser_n = 0; if (RI) { RI = 0;//先把接收标志给清零 if (SBUF == 0x7f) //9600波特率 { //接收命令为0x7f时就++ Uart1_ser_n++; if(Uart1_ser_n > 10)//大于10基本就是确定是下载命令 { Uart1_ser_n = 0; //然后执行软复位 IAP_CONTR |= 0xe0; } } } if (TI) { TI = 0;//先把发送标志给清零 //数据全部发送完成后标志位置1 //置1后是准备发送后一个字节 Uart1_Flag = 1; //调用串口发送函数 Uart1_Up_Data_Drive(); }}
我们可以看到接收缓冲区啥也没有,那就是因为发送缓冲区没有数据发送,单片机也就没有数据接收,标志没置1,然后单片机发送数据就没有一个触发的引子
我们发送任意数据都可以,只要单片机接收到数据就行,然后串口标志就会置1,使得串口发送函数有用,我们就可以看到电压显示出来,但是细心的同学会发现,我的发送汉字缓冲区明明是换行回车,你这也没看到啊,那是SPI软件有点小毛病,我们换个软件
所以知道为什么我在发送汉字缓冲区中写换行回车了吗
#include "all.h"//需要显示串口的临时变量bit Uart1_Flag = 1;//汉字是固定的 直接code//串口发送汉字数组缓存 先换行/n回车/ru8 code Uart1_Up_Symbol_Buffer[30] = {"/n/r电压: "};//串口发送数字数组缓存 20个足够以后用的了u8 xdata Uart1_Up_Num_Buffer[20];//串口1初始化void Uart1_Init(){ SM0 = 0; SM1 = 1; REN = 1; //上面三条语句就等于操作SCON |= 0x50; PCON &= 0x3f; AUXR |= 0x01; AUXR |= 0x14; T2H = 0xfd; T2L = 0x8f; ES = 1;}//串口发送底层驱动的函数void Uart1_Up_Data_Drive(){ static xdata u8 count = 0; //串口1标志为1才能发送字节, //可以让数据有效的发送 if(Uart1_Flag) { Uart1_Flag = 0; count++; switch (count) { case 1: SBUF = Uart1_Up_Symbol_Buffer[0];break; case 2: SBUF = Uart1_Up_Symbol_Buffer[1];break; case 3: SBUF = Uart1_Up_Symbol_Buffer[2];break; case 4: SBUF = Uart1_Up_Symbol_Buffer[3];break; case 5: SBUF = Uart1_Up_Symbol_Buffer[4];break; case 6: SBUF = Uart1_Up_Symbol_Buffer[5];break; case 7: SBUF = Uart1_Up_Symbol_Buffer[6];break; case 8: SBUF = Uart1_Up_Symbol_Buffer[7];break; case 9: SBUF = Uart1_Up_Symbol_Buffer[8];break; case 10:SBUF = Uart1_Up_Symbol_Buffer[9];break; case 12:SBUF = Uart1_Up_Num_Buffer[0];break; case 14:SBUF = Uart1_Up_Num_Buffer[1];break; case 16:SBUF = Uart1_Up_Num_Buffer[2];break; case 18:SBUF = Uart1_Up_Num_Buffer[3];break; case 20:SBUF = Uart1_Up_Num_Buffer[4];break; case 22:SBUF = Uart1_Up_Num_Buffer[5];break; case 24:count=0;break; } }}//串口1中断void Uart1_Routine() interrupt 4{ //记录接收命令流变量 static char Uart1_ser_n = 0; if (RI) { RI = 0;//先把接收标志给清零 //当接收到一个字节时,串口标志置1 Uart1_Flag = 1; if (SBUF == 0x7f) //9600波特率 { //接收命令为0x7f时就++ Uart1_ser_n++; if(Uart1_ser_n > 10)//大于10基本就是确定是下载命令 { Uart1_ser_n = 0; //然后执行软复位 IAP_CONTR |= 0xe0; } } } if (TI) { TI = 0;//先把发送标志给清零 //数据全部发送完成后标志位置1 //置1后是准备发送后一个字节 Uart1_Flag = 1; //调用串口发送函数 Uart1_Up_Data_Drive(); }}
#ifndef Uart1_Drive#define Uart1_Drive//外部声明extern void Uart1_Init();extern bit Uart1_Flag;extern void Uart1_Up_Data_Drive();extern u8 xdata Uart1_Up_Num_Buffer[20];#endif
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/123696.html
摘要:复位后初值是子函数调用,中断响应过程调用子函数处理中断响应的时候,程序计数器的值以及相关数据会先压入堆栈,然后去处理子函数中断服务。联动文章身家过亿的帝都富豪对小码农说你时空复杂度会了吗 ...
摘要:行列总共使用个口,可以扫描个按键的开关状态,这就是矩阵键盘的优势。口之间必须串联电阻。 文章目录 小码农为了总裁,咳咳,为了知识敢说按键不会吗?==**帝都富豪与...
摘要:否则可能会导致电平颠倒完美的计数糟糕的线条再来一个测试组我们来实现一个呼吸灯的效果呼吸灯波形为了贤淑妻子,咳咳,贤淑才女,小码农必定让控制时间什么是脉宽调制中间动的线是电流线,电流通断,电流小就暗,电流大就亮。 ...
摘要:对于电压或者电流连续变化的信号,就需要通过模数转换电路,变成单片机可以识别的数字电平信号。目前来说,常见的有两种方式,一种是并行比较,一种是逐次比较。具有成本低元件简单等优势,而且容易做出高精度的转换器,所以被广泛使用。 ...
摘要:前言今天下班突然看到一篇刷屏朋友圈的文章为什么甲骨文被裁员工不值得同情来自一个财经的微信公众号刚看题目我以为文章是会分析甲骨文公司内部的财经类问题所以就戳开看了毕竟本人不喜欢看打鸡血的文章。 为工薪层能合理取得报酬而发声,为大众选择不同生活状态都能获得尊重而发声,为不同职场层次的职场人都能有健康的工作环境而发声。 前言 今天下班突然看到一篇刷屏朋友圈的文章来自一个XX财经的微信公众号,...
阅读 2544·2021-11-18 10:02
阅读 1693·2021-09-30 10:00
阅读 5238·2021-09-22 15:27
阅读 1175·2019-08-30 15:54
阅读 3651·2019-08-29 11:13
阅读 2921·2019-08-29 11:05
阅读 3290·2019-08-29 11:01
阅读 548·2019-08-26 13:52