串口只有一条数据线一条地线, 所以数据是以串行方式发送的,所谓串行就是数据按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串口通信程序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)