谁和我说一下UART串口通信是如何接收发送数据的,while里面我这么编写, 下面是我的理解和问题

谁和我说一下UART串口通信是如何接收发送数据的,while里面我这么编写, 下面是我的理解和问题,第1张

串口只有一条数据线一条地线, 所以数据是以串行方式发送的,所谓串行就是数据按bit位依次发送,如下图

除了数据本身外一头一尾加上起始位和停止位(通知接收端表示数据的开始和结束), 有时还有校验位(发送数据的奇偶校验码), 取决于串口的工作方式

比如你在串口助手上发送字符串abc, 实际串口发送是发送字母a,再发送字母b,c等

再详细一点,字母a,二进制数表示是1100001, 发送它的流程是:

1)发送停止位

2)依次发送 1 0 0 0 0 1 1  (低位在前)

3)发送校验位

4)发送停止位

5)空闲

(下一字母发送)

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

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的时间,提高效率,

//摘要: 掌握 UART0配置及使用,程序中将UART0 配置到P00、 P01。利用串口调试助手,波特率设置为4800,并选择十六进制发送和显示,十六进制发送为偶数个,不然会少返回一个数,详见程序注释。

#include "c8051f020h"

unsigned char data1;

void SYSCLK_Init();

void PORT_Init();

void UART0_Init();

void SYSCLK_Init()

{

unsigned int i;

OSCXCN=0X67; //0X67=0110,0111

for(i=0;i<256;i++); //等待>1ms

while(!(OSCXCN&0X80)); //等待XTLVLD变为1

OSCICN=0X88; //时钟失效监测器,选择外部时钟源作为系统时钟

}

void PORT_Init()

{

XBR0 = 0x27;/交叉开关配置,URAT总线TX0置到P00口,RX0置到P01口, SPI总线SCK配置到P02口,

MOSI为P04口, NSS为P05,MISO配置到P03口,IIC总线SDA置到P06口�SCK置到P07 TX1,RX1配置到P10,P11, CEX0,CEX1,配置到P12,P13,外部中断int0配置到P14 /

XBR1 = 0x04;

XBR2 = 0x44; /允许功能选择开关有效/

P0MDOUT = 0x1A;/SCK、MOSI和NSS为推拉式输出,MISO为开漏式/

P74OUT =0xff;

}

void UART0_Init()

{

SCON0=0x50; //串口方式1

TMOD=0X20; //选用定时器1作为波特率发生器

TH1=0xF4; //波特率为4800

TL1=0xF4;

ES0=1; //开启串口中断0

TF1=0;

TR1=1; //定时器启动

PCON=0X80; //波特率加倍 波特率为9600

TI0=1;

}

void UART0_ISR() interrupt 4 using 1

{

if(RI0)

{

RI0=0;//中断接收标志清零

data1=SBUF0;//接收数据

SBUF0=data1;//发送数据

while(TI0==0);

TI0=0;//发送标志清零

}

}

main()

{

WDTCN=0XDE;

WDTCN=0XAD;

SYSCLK_Init();

PORT_Init();

UART0_Init();

EA=1;

while(1);

}

针对 树莓派 封装的 UWP应用 类,以下代码未经测试,聊以抛砖引玉:

using System;

using SystemCollectionsGeneric;

using SystemLinq;

using SystemText;

using SystemThreadingTasks;

using WindowsDevicesGpio;

using WindowsStorageStreams;

using WindowsDevicesEnumeration;

using WindowsDevicesSerialCommunication;

using WindowsDevicesI2c;

using WindowsDevicesSpi;

namespace SlotAgentAppServices

{

public class DevicesHelper

{

public static void GPIO(int eLevel=0, int ioPortNumber = 5)

{

// 获得系统板载缺省GPIO controller

GpioController gpio = GpioControllerGetDefault();

if (gpio == null)

return; // 如果系统板载无可用GPIO,则返回

// 打开指定的GPIO

using (GpioPin pin = gpioOpenPin(ioPortNumber))

{

// Latch HIGH value first This ensures a default value when the pin is set as output

pinWrite(eLevel==0 GpioPinValueLow: GpioPinValueHigh);

// 设置IO为输出方向

pinSetDriveMode(GpioPinDriveModeOutput);

} //关闭 pin - will revert to its power-on state

}

#region 示例代码

/

(一)GPIO接口使用

/

public void GPIO()

{

// Get the default GPIO controller on the system

GpioController gpio = GpioControllerGetDefault();

if (gpio == null)

return; // GPIO not available on this system

// Open GPIO 5

using (GpioPin pin = gpioOpenPin(5))

{

// Latch HIGH value first This ensures a default value when the pin is set as output

pinWrite(GpioPinValueHigh);

// Set the IO direction as output

pinSetDriveMode(GpioPinDriveModeOutput);

} // Close pin - will revert to its power-on state

}

/

(二) UART接口

Pin 8 - UART0 TX

Pin 10- UART0 RX

下面的例子先是初始化UART0,然后做了一次读 *** 作和一次写 *** 作

/

public async void Serial()

{

string aqs = SerialDeviceGetDeviceSelector("UART0"); / Find the selector string for the serial device /

var dis = await DeviceInformationFindAllAsync(aqs); / Find the serial device with our selector string /

SerialDevice SerialPort = await SerialDeviceFromIdAsync(dis[0]Id); / Create an serial device with our selected device /

/ Configure serial settings /

SerialPortWriteTimeout = TimeSpanFromMilliseconds(1000);

SerialPortReadTimeout = TimeSpanFromMilliseconds(1000);

SerialPortBaudRate = 9600;

SerialPortParity = SerialParityNone;

SerialPortStopBits = SerialStopBitCountOne;

SerialPortDataBits = 8;

/ Write a string out over serial /

string txBuffer = "Hello Serial";

DataWriter dataWriter = new DataWriter();

dataWriterWriteString(txBuffer);

uint bytesWritten = await SerialPortOutputStreamWriteAsync(dataWriterDetachBuffer());

/ Read data in from the serial port /

const uint maxReadLength = 1024;

DataReader dataReader = new DataReader(SerialPortInputStream);

uint bytesToRead = await dataReaderLoadAsync(maxReadLength);

string rxBuffer = dataReaderReadString(bytesToRead);

}

/

使用上面的例子时,需要在Packageappxmanifest 中修改下权限修改如下

<Capabilities>

<DeviceCapability Name="serialcommunication">

<Device Id="any">

<Function Type="name:serialPort" />

</Device>

</DeviceCapability>

</Capabilities>

/

/

(三)I2C 总线

Pin 3 - I2C1 SDA

Pin 5 - I2C1 SCL

下面的例子首先初始化I2C1 然后向地址为0x40的I2C设备写数据

/

public async void I2C()

{

// Get a selector string for bus "I2C1"

string aqs = I2cDeviceGetDeviceSelector("I2C1");

// Find the I2C bus controller with our selector string

var dis = await DeviceInformationFindAllAsync(aqs);

if (disCount == 0)

return; // bus not found

// 0x40 is the I2C device address

var settings = new I2cConnectionSettings(0x40);

// Create an I2cDevice with our selected bus controller and I2C settings

using (I2cDevice device = await I2cDeviceFromIdAsync(dis[0]Id, settings))

{

byte[] writeBuf = { 0x01, 0x02, 0x03, 0x04 };

deviceWrite(writeBuf);

}

}

/

(四) SPI 总线

Pin 19 - SPI0 MOSI

Pin 21 - SPI0 MISO

Pin 23 - SPI0 SCLK

Pin 24 - SPI0 CS0

Pin 26 - SPI0 CS1

下面的例子向SPI0 做了一次写 *** 作

/

public async void SPI()

{

// Get a selector string for bus "SPI0"

string aqs = SpiDeviceGetDeviceSelector("SPI0");

// Find the SPI bus controller device with our selector string

var dis = await DeviceInformationFindAllAsync(aqs);

if (disCount == 0) ;

return; // "SPI0" not found on this system

// Use chip select line CS0

var settings = new SpiConnectionSettings(0);

// Create an SpiDevice with our bus controller and SPI settings

using (SpiDevice device = await SpiDeviceFromIdAsync(dis[0]Id, settings))

{

byte[] writeBuf = { 0x01, 0x02, 0x03, 0x04 };

deviceWrite(writeBuf);

}

}

#endregion

}

}

1、如果要发送数据,将发送数据a赋给dat即主函数main{}里面写a=dat;就可以了

2、如果要发送一串数字,则定义一个数组,然后用for循环赋值就可以了

3、如果电脑以十六进制显示,则程序里面发的是十进制数,或者是字符,需在串口中断手动设置为十六进制显示即可

希望可以帮到你,如果!

以上就是关于谁和我说一下UART串口通信是如何接收发送数据的,while里面我这么编写, 下面是我的理解和问题全部的内容,包括:谁和我说一下UART串口通信是如何接收发送数据的,while里面我这么编写, 下面是我的理解和问题、如何实现2个51单片机之间通过串口通信的源程序、求c8051F020的UART串口通信程序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

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

原文地址: http://outofmemory.cn/zz/10209358.html

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

发表评论

登录后才能评论

评论列表(0条)

保存