单片机串行通信程序调试原因

单片机串行通信程序调试原因,第1张

串口UART作为嵌入式应用和通讯领域中最常用的接口之一,接口协议虽然简单,但在实际应用中不同设备之间的通讯也会存在各种小问题,下面对使用中各种常见的问题做下总结和梳理,可作为调试参考。串口可分为异步串口(UART)和同步串口(USART),后者多出时钟信号线用作通讯时信号同步。本偏仅介绍异步串口。

一、串口通信常见问题

串口通信乱码

串口通讯乱码通常是指接收方接收到的数据不符合预期,出现此情况时需要考虑的因素通常包含以下几个方面:

双方设定的串口参数是否匹配,需检查设置的:串口波特率、串口数据格式等参数。

串口通讯电压不匹配,不同的串口设备接收可正常进行解码的高低电平门限不同,如同样是33V串口通讯,A设备低电平门限15V,B设备低电平门限1V。当实际串口电压低电平只有15V时,B设备无法正常接收数据。又如:A设备为5V串口,B设备为33V串口,同样有电压不匹配的问题。

串口通讯实际工作波特率误差较大,即:串口工作实际波特率和理论值偏差较大,因一些MCU和串口设备所用时钟为了兼顾其他资源和应用需要,实际工作的串口速率和设定会有偏差。比如:标称为9600bps时,实际工作在了10000bps(误差超过4%),此时可能已经超出接收方的设计标准。

串口通讯信号质量差,如通讯时信号上升下降抖动严重,信号有过冲或者变化比较迟缓,此时检查硬件上共地是否良好,以及线路上有无串接/并联其他器件导致。

数据格式显示问题,通常使用十六进制或ASCII码格式居多,使用时需要区分。

串口无法发送

串口无法发送通常是指与此串口的TXD连接的对端设备RXD通道接收不到任何数据,总结如下:

使用仪器对TXD通道进行实际测量,观察硬件波形,确定信号是否有输出以及是否正常。(串口电压、串口信号上升下降时间)

短接设备的TXD和RXD通道回环测试,看自收发是否可以成功。排除是自身设备异常还是对端异常。

确定应用软件是否打开串口硬件流控,如当启用RTS/CTS硬件流控后但实际该引脚并没有连接或连接但不生效时,按照协议规定,CTS输入无效则发送方暂停发送数据。

MCU软件编码问题或计算机端软件工作异常。

串口无法接收

当串口接收不到任何数据的原因通常如下:

对端串口实际未能成功发送数据。

串口发送有效电压不满足芯片接收解码要求。

MCU软件编码问题或计算机端软件工作异常。

二、常用的排查小技巧

对于以上的常见串口调试问题,有以下几个方法和技巧可供参考使用。

使用硬件仪器

善于使用示波器等硬件采集或分析工具查找问题,用此方法可以确定线路上信号的串口电压、串口数据格式、串口通信波特率等参数。

串口Loopback检测

当手头没有硬件仪器时,将设备自身的TXD和RXD短接起来进行自收发测试也是一个不错的选择,此方式可以简单确认硬件通路和整个逻辑是否是打通的。但缺点是定位问题不够精准。

更换串口调试软件

计算机端串口软件种类较多,不排除一些设备或驱动软件没法成功适配所有的串口调试软件,此时可尝试多使用几款不同的软件对比测试。

三、串口通信基础

当两个设备使用UART进行通信时,它们至少通过三根导线连接:TXD串口发送、RXD串口接收、GND。串口设备通过改变TXD信号线上的电压来发送数据,接收端通过检测RXD线上的电压来读取数据。

什么是串口通信

计算机一次传输信息(数据)一位或多个比特位。串行是指传输数据一次只传输一位。当进行串口通信时发送或者接收的每个字(即字节或字符)一次发送一位。每一位都是逻辑‘1’或者‘0’。也用Mark表示逻辑1,Space表示逻辑0。

串口数据速率使用 bits-per-second ("bps") 或者 baud rate ("baud")。这表示一秒内可以传输多少逻辑1和0。当波特率超过 1000,你会经常看到用Kbps表示的速率。对于超过 1000000 的速率一般用Mbps 来表示。

4月22日修改

我用过AT89C51的,AT89C52应该差不多吧

希望下面一段程序对你有所帮助

//-----------------------函数声明,变量定义--------------------------------------------------------

#include <reg51h>

#define COUNT 10 // 定义接收缓冲区大小

unsigned char buffer[COUNT]; //定义接收缓冲区

unsigned char point; //定义接收数据个数指示变量

void UART_init(); //串口初始化函数

void COM_send(void); //串口接收函数

unsigned char CLU_checkdata(void);//计算校验位函数

//--------------------------------------------------------------------------------------------------

// 函数名称: UART_init()串口初始化函数

// 函数功能: 在系统时钟为11059MHZ时,设定串口波特率为9600bit/s 字串9

// 串口接收中断允许,发送中断禁止

//--------------------------------------------------------------------------------------------------

void UART_init()

{

//初始化串行口和波特率发生器

SCON =0x58; //选择串口工作方式,打开接收允许

TMOD =0x21; //定时器1工作在方式2,定时器0工作在方式1

TH1 =0xfd; //实现波特率9600(系统时钟110592MHZ)

TR1 =1; //启动定时器T1

ET1 =0;

ES=1; //允许串行口中断

PS=1; //设计串行口中断优先级

字串7

EA =1; //单片机中断允许

}

//--------------------------------------------------------------------------------------------------

// 函数名称: com_interrup()串口接收中断处理函数

// 函数功能: 接收包括起始位'S'在内的十位数据到数据缓冲区

//--------------------------------------------------------------------------------------------------

com_interrupt(void) interrupt 4 using 3

{

unsigned char RECEIVR_buffer;

if(RI) //处理接收中断

{

RI=0; //清除中断标志位 字串5

RECEIVR_buffer=SBUF; //接收串口数据

if(point==0) //如果还没有接收到起始位

{

if(RECEIVR_buffer=='S') //判断是否起始标志位

point++; //是准备接收下一位

else

point=0; //不是,继续等待起始位

}

else if(point>0&&point<10) //判断是否接收够十位数据

buffer[point++]=RECEIVR_buffer; //不够,把接收到的数据放入接收缓存区

else point=0; //缓冲区已满,清除缓存区内数据重新接收

字串5

}

If(TI) //处理发送中断

{

TI=0;

}

}

//--------------------------------------------------------------------------------------------------

// 函数名称: COM_send()串口发送函数

// 函数功能: 把数据缓冲区的十位数据发送出去

//--------------------------------------------------------------------------------------------------

void COM_send(void)

{

for(point=0;point<=10,TI=1;point++) //连续发送十位数据

//把缓存区的数据都发送到串口

{

SBUF=buffer[point];

字串1

TI=0;

}

}

//--------------------------------------------------------------------------------------------------

// 函数名称: CLU_checkdata()计算校验位函数

// 输入变量: 无

// 输出变量: checkdata,包括起始位在内的前九位数据的校验和

// 函数功能: 计算校验和

//--------------------------------------------------------------------------------------------------

unsigned char CLU_checkdata(void)

{ //计算校验位

unsigned char checkdata=0;

for(point=0;point<9,TI=1;point++)

{

checkdata=checkdata|buffer[point];

}

return(checkdata);

}

//--------------------------------------------------------------------------------------------------

// 函数名称: 主函数

// 函数功能: 调度个子函数,完成通信过程 字串1

//--------------------------------------------------------------------------------------------------

void main(void)

{

unsigned char checkdata;

do

{

UART_init(); //初始化串口

if(point==10) //判断数据是否接收完成

checkdata=CLU_checkdata; //调用求校验和函数

if(checkdata==buffer[9]) //判断校验和是否正确

COM_send();

//正确则调用发送程序

point=0;

}

while(1);

}

汇编编写的模拟串口通信程序

T2作为波特率控制

UART_RXD 是硬中断0或1口,如果能进入中断,说明该线有一个起始位产生,进入中断后调

用下面的接收程序。退出硬中断之前还需要将硬中断标志重新复位。

UART_TXD 是任何其它IO即可。

UART_SEND:

PUSH IE

PUSH DPH

PUSH DPL

PUSH PSW

PUSH 00H

PUSH ACC

CLR EA

SETB UART_TXD ;START BIT

MOV R0,A

CLR TR2 ;TR2置1,计数器2启动,时间计数启动。

MOV A,RCAP2L;计数器2重新装载值

MOV TL2,A ;置计数器2初值 ;T2需要重新装载

MOV A,DPH

MOV A,RCAP2H

MOV TH2,A

MOV A,R0

SETB TR2 ;TR2置1,计数器

JNB TF2,$

CLR TF2

JNB TF2,$

CLR TF2

CLR UART_TXD ;START BIT

JNB TF2,$

CLR TF2

JNB TF2,$

CLR TF2

MOV R0,#08H

UART_SEND_LOOP:

RRC A

MOV UART_TXD,C ;8 BIT

JNB TF2,$

CLR TF2

JNB TF2,$

CLR TF2

DJNZ R0,UART_SEND_LOOP

SETB UART_TXD ;END BIT

JNB TF2,$

CLR TF2

JNB TF2,$

CLR TF2

POP ACC

POP 00H

POP PSW

POP DPL

POP DPH

POP IE

RET

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

UART_REC:

PUSH IE

PUSH DPH

PUSH DPL

CLR EA

CLR TR2 ;TR2置1,计数器2启动,时间计数启动。

MOV A,RCAP2L;计数器2重新装载值

MOV TL2,A ;置计数器2初值 ;T2需要重新装载

MOV A,DPH

MOV A,RCAP2H

MOV TH2,A

JB UART_RXD,$ ;REC

SETB TR2 ;TR2置1,计数器2启动,时间计数启动。

JNB TF2,$

CLR TF2 ;05 BIT

JNB TF2,$

CLR TF2 ;1 BIT

JNB TF2,$

CLR TF2 ;15 BIT

MOV C,UART_RXD

MOV ACC0,C

JNB TF2,$

CLR TF2

JNB TF2,$

CLR TF2 ;25

MOV C,UART_RXD

MOV ACC1,C

JNB TF2,$

CLR TF2

JNB TF2,$

CLR TF2 ;35

MOV C,UART_RXD

MOV ACC2,C

JNB TF2,$

CLR TF2

JNB TF2,$

CLR TF2 ;45

MOV C,UART_RXD

MOV ACC3,C

JNB TF2,$

CLR TF2

JNB TF2,$

CLR TF2 ;55

MOV C,UART_RXD

MOV ACC4,C

JNB TF2,$

CLR TF2

JNB TF2,$

CLR TF2 ;65

MOV C,UART_RXD

MOV ACC5,C

JNB TF2,$

CLR TF2

JNB TF2,$

CLR TF2 ;75

MOV C,UART_RXD

MOV ACC6,C

JNB TF2,$

CLR TF2

JNB TF2,$

CLR TF2 ;85

MOV C,UART_RXD

MOV ACC7,C

JNB TF2,$

CLR TF2 ;95

JNB UART_RXD,$ ;等待停止位,并重新复位计数器

SETB UART_RXD

POP DPL

POP DPH

POP IE

RET

补充回答:

串口调试

1 发送:向总线上发命令

2 接收:从总线接收命令,并分析是地址还是数据。

3 定时发送:从内存中取数并向主机发送

经过调试,以上功能基本实现,可以通过上位机对单片机进行实时控制。

程序如下:

//这是一个单片机C51串口接收(中断)和发送例程,可以用来测试51单片机的中断接收

//和查询发送,发送没有必要用中断,因为程序的开销是一样的

#include <reg51h>

#include<stdioh>

#include <stringh>

#define INBUF_LEN 4 //数据长度

unsigned char inbuf1[INBUF_LEN];

unsigned char checksum,count3 , flag,temp,ch;

bit read_flag=0;

sbit cp=P1^1;

sbit DIR=P1^2;

int i;

unsigned int xdata RAMDATA; /定义RAM地址指针/

unsigned char a[6] ={0x11,0x22,0x33,0x44,0x55,0x66} ;

void init_serialcomm(void)

{

SCON=0x50; //在110592MHz下,设置串行口波特率为9600,方式1,并允许接收

PCON=0x00;

ES=1;

TMOD=0x21; //定时器工作于方式2,自动装载方式

TH0=(65536-1000)%256;

TL0=(65536-1000)/256;

TL1=0xfd;

TH1=0xfd;

ET0=1;

TR0=1;

TR1=1;

// TI=0;

EA=1;

// TI=1;

RAMDATA=0x1F45;

}

void serial () interrupt 4 using 3

{

if(RI)

{ RI=0;

ch=SBUF;

TI=1; //置SBUF空

switch(ch)

{

case 0x01 :printf("A"); TI=0;break;

case 0x02 :printf("B"); TI=0;break;

case 0x03 :printf("C"); TI=0;break;

case 0x04 :printf("D"); TI=0;break;

default :printf("fg"); TI=0;break;

}

}

}

//向串口发送一个字符

void timer0() interrupt 1 using 3{

// char i;

flag++;

TH0=0x00;

TL0=0x00;

if(flag==10)

{// cp=!cp;

// for(i=0;i<6;i++)

P2=0x25;

TI=1;

temp=RAMDATA;

printf("%c",temp);

TI=0;

// RAMDATA--;

flag=0;

}

}

//主程序

main()

{

init_serialcomm(); //初始化串口

//向6264中送数据

{

RAMDATA=0x33;

}

while(1)

{

RAMDATA=0x33;;

}

}

调试需要注意的问题:

1 发送过程:在发送时必须保证TI=1:即发送缓冲器为空,否则将导致数据发不出去,如果想强制发送可以用:TI=1具体发送数据:利用printf(“abcd”);函数直接发送即可。

2 接收过程:在接收时多选用中断方式,这样可以节约CPU的时间,提高效率,

姓名:吕红霞;学号:20011210203;学院:通信工程学院

转自>

要求用什么语言?

------------------------------

网友“星心晨梦”的回答,是可以满足题目要求的。

我实验了,是成功的,没有任何错误。

楼主应该检查自己的电路、串口设置等等。

------------------------------

网友“星心晨梦”的回答,篇幅稍稍长了一些。

缩减一半就可以正常工作了,可读性更好一些。

建议看看下面的。

------------------------------

#include <AT89X51h>

#include <intrinsh>

#define uchar unsigned char

#define uint unsigned int

//---------------------------------------------------

uchar idata trdata1[] = {

'W','E','L','C','O','M','E',' ','T','O',' ','C','H','I','N','A','!',0x0d,0,0x00};

uchar idata trdata2[] = {

'M','Y',' ','N','A','M','E',' ','I','S',' ','L','I','M','I','N','G',0x0d,0,0x00};

uchar idata trdata3[] = {

'Y','I','N','G','Y','O','N','G','K','E','X','U','E','X','U','E','Y','U','A','N',0x0d,0,0x00};

uchar RxBuf[5], Rx_p, Rx_i, TX_p, Tx_i;

//---------------------------------------------------

void UART_Init(void) //串口初始化

{

PCON = 0x00;

SCON = 0x50; //串口工作方式为1,允许接收

TMOD = 0x20; // T1 定时方式2

TH1 = 0xfd; //波特率 9600bps @ fosc = 110592MHz

TL1 = 0xfd;

TR1 = 1; //启动T1

ES = 1; //开串口中断

EA = 1; //开总中断

}

//---------------------------------------------------

void main()

{

UART_Init();

Rx_p = 0;

Rx_p = 2;

while(1) {

if (Rx_p != 0) {

TX_p = Rx_p;//字符串1 2 3

Tx_i = 0; //字符指针

Rx_p = 0; //清零

Rx_i = 0;

TI = 1; //启动发送中断

} }

}

//---------------------------------------------------

void Uart_INT(void) interrupt 4 //串口中断函数

{

uchar Tcv = 0;

if(RI) { //接收?

RI = 0; //标志位清零

RxBuf[Rx_i] = SBUF;

if((RxBuf[Rx_i - 1] == 'g') && (RxBuf[Rx_i] == 'o')) Rx_p = 1;

if((RxBuf[Rx_i - 2] == 'w') && (RxBuf[Rx_i - 1] == 'h') && (RxBuf[Rx_i] == 'o')) Rx_p = 2;

if((RxBuf[Rx_i - 3] == 'h') && (RxBuf[Rx_i - 2] == 'o') && (RxBuf[Rx_i - 1] == 'm') && (RxBuf[Rx_i] == 'e')) Rx_p = 3;

P1 = Rx_p; //在P1显示收到的信息

Rx_i++;

Rx_i %= 5;

}

else {

TI = 0;

if (TX_p == 1) Tcv = trdata1[Tx_i]; //取来待发字符

if (TX_p == 2) Tcv = trdata2[Tx_i];

if (TX_p == 3) Tcv = trdata3[Tx_i];

if (Tcv != 0) {SBUF = Tcv; Tx_i++;} //不是0就发送

}

}

//---------------------------------------------------

以上就是关于单片机串行通信程序调试原因全部的内容,包括:单片机串行通信程序调试原因、求用keilc编写一串口通信程序、如何实现2个51单片机之间通过串口通信的源程序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zz/10089555.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-05
下一篇2023-05-05

发表评论

登录后才能评论

评论列表(0条)

    保存