导航:首页 > 操作系统 > 51单片机单机串行通信程序

51单片机单机串行通信程序

发布时间:2022-05-29 23:27:05

❶ 两个51单片机串口通信程序

串行发送程序 Tx.asm :
PCON, #00H ;; 波特率不倍增
SETB TR1 ;; 启动定时器T1
MOV IE, #0 ;; 禁止任何中断
CALL DLY125 ;; 延时125ms
;;--------------------------------------------
T_X: ;; 透传发送字串

ACALL DSPLED ;; P2.0控制LED闪亮
MOV R3, #4 ;; 待发送字符个数
MOV DPTR, #TAB_TX ;; 数据表首址
TX_LP1: CLR A
MOVC A, @A+DPTR ;; A←数据表的1个字符
CLR TI ;; TI清零,允许发送
MOV SBUF,A ;; 发送1个字符
JNB TI, $ ;; 等待1个字符帧发送结束
DJNZ R3, TX_next
CALL DLY500 ;; 延时500ms
SJMP T_X ;; 重复发送
TX_next: ;; 发送另一字符
INC DPTR ;; 数据表指针移动
SJMP TX_LP1
;;--------------------------------------------
DSPLED: ;;开机或复位,P2.0控制LED闪亮6遍

MOV R2, #6 ;; 循环次数
LEDLP1: CLR P2.0 ;; LED亮
CALL DLY125 ;; 延时125ms
SETB P2.0 ;; LED灭
CALL DLY125
DJNZ R2,LEDLP1 ;; 循环
RET
;;----------------------------------------------
DLY125: ;; 延时125ms
DLY125A: MOV R5,#250
DLY125B: MOV R6,#250
DJNZ R6,$
DJNZ R5,DLY125B
RET
;; 250*250*2μs=125 000μs =125ms
;;----------------------------------------------
DLY500: ;; 延时500ms
MOV R7,#4
DLY500A: MOV R6,#250
DLY500B: MOV R5,#250
DJNZ R5,$
DJNZ R6,DLY500B
DJNZ R7,DLY500A
RET
;; 4*250*250*2μs=500 000μs =500ms
;;-------------------------------------------------

TAB_TX: DB 38H,30H,35H,31H, ...

;; 8 0 5 1 ...
;;----------------------------------------------
END

❷ 51单片机串口通信程序(需要判断)

#include<reg51.h>
#define uchar unsigned char
uchar com1[]={0xef,0x01,0xff,0xff,0xff,0xff,0x01,0x00,0x03,0x01,0x00,0x05};
uchar red1[]={0xef,0x01,0xff,0xff,0xff,0xff,0x07,0x00,0x03,0x02,0x00,0x0c};
uchar red2[]={0xef,0x01,0xff,0xff,0xff,0xff,0x07,0x00,0x03,0x02,0x00,0x0a};
uchar red3[]={0xef,0x01,0xff,0xff,0xff,0xff,0x07,0x00,0x03,0x02,0x80,0x0a};
sbit p17=P1^7;
sbit p10=P1^0;
sbit p11=P1^1;
sbit p12=P1^2;
main()
{
uchar i,rdat[12];
TMOD=0x20;
TH1=0xfd;
TL1=0xfd;
TR1=1;
SCON=0x50;
while(1)
{
for(i=0;i<12;i++)
{
SBUF=com1[i];
while(!TI);
TI=0;
}
i=0;
while(i<12)
{
if(RI)
{
RI=0;
rdat[i]=SBUF;
i++;
}
}
for(i=0;i<12;i++)
{
if(rdat[i]!=red1[i])p17=1;
}
for(i=0;i<12;i++)
{
SBUF=com1[i];
while(!TI);
TI=0;
}
i=0;
while(i<12)
{
if(RI)
{
RI=0;
rdat[i]=SBUF;
i++;
}
for(i=0;i<12;i++)
{
if(rdat[i]!=red2[i])p10=1;
else if(rdat[i]!=red2[i])p11=1;
else p12=1;
}
}
}
}

❸ 51单片机串口通讯

51单片机串口通信
来源:维库 作者:
关键字:51单片机 串口通信
这节我们主要讲单片机上串口的工作原理和如何通过程序来对串口进行设置,以及根据所给出的实例实现与PC 机通信。
一、原理简介
51 单片机内部有一个全双工串行接口。什么叫全双工串口呢?一般来说,只能接受或只能发送的称为单工串行;既可接收又可发送,但不能同时进行的称为半双工;能同时接收和发送的串行口称为全双工串行口。串行通信是指数据一位一位地按顺序传送的通信方式,其突出优点是只需一根传输线,可大大降低硬件成本,适合远距离通信。其缺点是传输速度较低。
与之前一样,首先我们来了解单片机串口相关的寄存器。
SBUF 寄存器:它是两个在物理上独立的接收、发送缓冲器,可同时发送、接收数据,可通过指令对SBUF 的读写来区别是对接收缓冲器的操作还是对发送缓冲器的操作。从而控制外部两条独立的收发信号线RXD(P3.0)、TXD(P3.1),同时发送、接收数据,实现全双工。
串行口控制寄存器SCON(见表1) 。

表1 SCON寄存器
表中各位(从左至右为从高位到低位)含义如下。
SM0 和SM1 :串行口工作方式控制位,其定义如表2 所示。

表2 串行口工作方式控制位
其中,fOSC 为单片机的时钟频率;波特率指串行口每秒钟发送(或接收)的位数。
SM2 :多机通信控制位。 该仅用于方式2 和方式3 的多机通信。其中发送机SM2 = 1(需要程序控制设置)。接收机的串行口工作于方式2 或3,SM2=1 时,只有当接收到第9 位数据(RB8)为1 时,才把接收到的前8 位数据送入SBUF,且置位RI 发出中断申请引发串行接收中断,否则会将接受到的数据放弃。当SM2=0 时,就不管第位数据是0 还是1,都将数据送入SBUF,并置位RI 发出中断申请。工作于方式0 时,SM2 必须为0。
REN :串行接收允许位:REN =0 时,禁止接收;REN =1 时,允许接收。
TB8 :在方式2、3 中,TB8 是发送机要发送的第9 位数据。在多机通信中它代表传输的地址或数据,TB8=0 为数据,TB8=1 时为地址。
RB8 :在方式2、3 中,RB8 是接收机接收到的第9 位数据,该数据正好来自发送机的TB8,从而识别接收到的数据特征。
TI :串行口发送中断请求标志。当CPU 发送完一串行数据后,此时SBUF 寄存器为空,硬件使TI 置1,请求中断。CPU 响应中断后,由软件对TI 清零。
RI :串行口接收中断请求标志。当串行口接收完一帧串行数据时,此时SBUF 寄存器为满,硬件使RI 置1,请求中断。CPU 响应中断后,用软件对RI 清零。
电源控制寄存器PCON(见表3) 。

表3 PCON寄存器

表中各位(从左至右为从高位到低位)含义如下。
SMOD :波特率加倍位。SMOD=1,当串行口工作于方式1、2、3 时,波特率加倍。SMOD=0,波特率不变。
GF1、GF0 :通用标志位。
PD(PCON.1) :掉电方式位。当PD=1 时,进入掉电方式。
IDL(PCON.0) :待机方式位。当IDL=1 时,进入待机方式。
另外与串行口相关的寄存器有前面文章叙述的定时器相关寄存器和中断寄存器。定时器寄存器用来设定波特率。中断允许寄存器IE 中的ES 位也用来作为串行I/O 中断允许位。当ES = 1,允许 串行I/O 中断;当ES = 0,禁止串行I/O 中断。中断优先级寄存器IP的PS 位则用作串行I/O 中断优先级控制位。当PS=1,设定为高优先级;当PS =0,设定为低优先级。
波特率计算:在了解了串行口相关的寄存器之后,我们可得出其通信波特率的一些结论:
① 方式0 和方式2 的波特率是固定的。
在方式0 中, 波特率为时钟频率的1/12, 即fOSC/12,固定不变。
在方式2 中,波特率取决于PCON 中的SMOD 值,即波特率为:

当SMOD=0 时,波特率为fosc/64 ;当SMOD=1 时,波特率为fosc/32。
② 方式1 和方式3 的波特率可变,由定时器1 的溢出率决定。

当定时器T1 用作波特率发生器时,通常选用定时初值自动重装的工作方式2( 注意:不要把定时器的工作方式与串行口的工作方式搞混淆了)。其计数结构为8 位,假定计数初值为Count,单片机的机器周期为T,则定时时间为(256 ?Count)×T 。从而在1s内发生溢出的次数(即溢出率)可由公式(1)所示:

从而波特率的计算公式由公式(2)所示:

在实际应用时,通常是先确定波特率,后根据波特率求T1 定时初值,因此式(2)又可写为:

51单片机串口通讯

二、电路详解

下面就对图1 所示电路进行详细说明。
图1 串行通信实验电路图
最小系统部分(时钟电路、复位电路等)第一讲已经讲过,在此不再叙述。我们重点来了解下与计算机通信的RS-232 接口电路。可以看到,在电路图中,有TXD 和RXD 两个接收和发送指示状态灯,此外用了一个叫MAX3232 的芯片,那它是用来实现什么的呢?首先我们要知道计算机上的串口是具有RS-232 标准的串行接口,而RS-232 的标准中定义了其电气特性:高电平“1”信号电压的范围为-15V~-3V,低电平“0”
信号电压的范围为+3V~+15V。可能有些读者会问,它为什么要以这样的电气特性呢?这是因为高低电平用相反的电压表示,至少有6V 的压差,非常好的提高了数据传输的可靠性。由于单片机的管脚电平为TTL,单片机与RS-232 标准的串行口进行通信时,首先要解决的便是电平转换的问题。一般来说,可以选择一些专业的集成电路芯片,如图中的MAX3232。MAX3232 芯片内部集成了电压倍增电路,单电源供电即可完成电平转换,而且工作电压宽,3V~5.5V 间均能正常工作。其典型应用如图中所示,其外围所接的电容对传输速率有影响,在试验套件中采用的是0.1μF。
值得一提的是MAX3232 芯片拥有两对电平转换线路,图中只用了一路,因此浪费了另一路,在一些场合可以将两路并联以获得较强的驱动抗干扰能力。此外,我们有必要了解图中与计算机相连的DB-9 型RS-232的引脚结构(见图2)。

图2 DB-9连接器接口图
其各管脚定义如下(见表4)。

表4 DB-9型接口管脚定义
三、程序设计
本讲设计实例程序如下:
#include "AT89X52.h" (1)
void Init_Com(void) ( 2)
{
TMOD = 0x20; ( 3)
PCON = 0x00; ( 4)
SCON = 0x50; ( 5)
TH1 = 0xE8; ( 6)
TL1 = 0xE8; ( 7)
TR1 = 1; ( 8)
}
void main(void) ( 9)
{
unsigned char dat; ( 10)
Init_Com(); ( 11)
while(1) ( 12)
程序详细说明:
(1)头文件包含。
(2)声明串口初始化程序。
(3)设置定时器1 工作在模式2,自动装载初值(详见第二讲)。
(4)SMOD 位清0,波特率不加倍。
(5)串行口工作在方式1,并允许接收。
(6)定时器1 高8 位赋初值。波特率为1200b/s(7)定时器1 低8 位赋初值。
(8)启动定时器。
(9)主函数。
(10)定义一个字符型变量。
(11)初始化串口。
(12)死循环。
(13)如果接收到数据。
(14)将接收到的数据赋给之前定义的变量。
(15)将接收到的值输出到P0 口。
(16)对接收标志位清0,准备再次接收。
(17)将接收到的数据又发送出去。
(18)查询是否发送完毕。
(19)对发送标志位清0。
四、调试要点与实验现象
接好硬件,通过冷启动方式将程序所生成的。hex文件下载到单片机运行后,打开串口调试助手软件,设置好波特率1200,复位单片机,然后在通过串口调试助手往单片机发送数据(见图3),可以观察到在接收窗口有发送的数据显示,此外电路板上的串行通信指示灯也会闪烁,P0 口所接到LED 灯会闪烁所接收到的数据。

图3 串口软件调试界面
另外串口调试助手软件使用时应注意的是,如果单片机开发板采用串口下载而且和串口调试助手是使用同一串口,则在打开串口软件的同时不能给单片机下载程序,如需要下载,请首先点击“关闭串口”,做发送实验的时候,注意如果选中16 进制发送的就是数字或者字母的16 进制数值,比如发送“0”,实际接收的就应该是0x00,如果不选中,默认发送的是ASCII 码值,此时发送“0”,实际接收的就应该是0x30,这点可以通过观察板子P0 口上的对应的LED 指示出来。
五、总结
本讲介绍了单片机串口通信的原理并给出了实例,通过该讲,读者可以了解和掌握51 单片机串口通信的原理与应用流程,利用串口通信,单片机可以与计算机相连,也可以单片机互联或者多个单片机相互通信组网等,在实际的工程应用中非常广泛。从学习的角度来说,熟练的利用串口将单片机系统中的相关信息显示在计算机上可以很直观方便的进行调试和开发。

❹ 高分求51单片机串口通信的程序

利用方式1实现单片机双机通信,主频为6M,波特率为2400bps,电路见图5-10。当两个单片机距离较近时,甲、乙两机的发送端与接收端分别直接相联,两机共地。执行程序,甲机将亮灯信号发送给乙机,若通信正常,乙机接收到信号后点亮20个发光二极管。乙机采用查询与中断两种工作方式。当然20个LED乙机可单独控制,也可接受甲机的控制,并执行甲机指令,还需要进一步完善程序.
甲机发送程序:
org 0000h
sta: mov tmod,#20h ;设置波特率
mov tl1,#0FAh
mov th1,#0FAh
setb tr1
mov scon,#40h ;置工作方式1
clr ti
mov a,#00h
mov sbuf,a ;发送亮灯信号
wait: jbc ti,cont ;发送成功清标志
ajmp wait ;等待发送完毕
cont: sjmp sta ;重复发送
end

乙机查询工作方式接收:

org 0000h
mov tmod,#20h ;设置通信波特率
mov tl1,#0FAh
mov th1,#0FAh
setb tr1
mov scon,#40h
clr ri
setb ren ;允许接收
wait: jbc ri,read ;接收成功清标志
ajmp wait ;接收未完等待
read: mov a ,sbuf
mov p1,a ;接收亮灯信号送P1口
sjmp $
end

乙机中断工作方式接收
org 0000h
ajmp main
org 0023h
ajmp zd ;转串口中断程序
START: MOV TMOD,#20h
mov tl1,#0FAh
mov th1,#0FAh
setb tr1
mov scon,#50h
clr ri
mov ie,#90h ;开中断

MAIN:sjmp $ 主程序
zd: clr ri ;清接收标志
;==============中断程序还要再完善==============
mov a ,sbuf ;读接收信号
mov p1,a
MOV R1,A ;将收到的信号送缓存
reti ;中断返回
end

采用方式2 通信,数据帧格式是11位的,TB8为奇偶校验位,接收过程要求判断RB8,若出错置F0标志为1,正确则置F0标志为0,然后返回。发送波特率375kbps,晶振为12MHz,所以SMOD=l。由于传送数据的波特率与定时器无关,所以程序中无需对定时器编程.

send:
MOV SCON,#80H ;设置串行口为方式2
MOV PCON,#80H ;SMOD=l
MOV R0,#50H ;设数据块指针
MOV R7,#20 ;设数据块长度
STA: MOV A,@R0 ;取数据给A
MOV C,P
MOV TB8,C ;奇偶位P送给TB8,
MOV SBUF,A ;启动发送
;====================================================
WAIT: JBC TI,CONT ;若发完一帧数据,清标志后发下一帧数据
AJMP WAIT ;未完等待
;=======================================================
CONT:INC R0 ;修改数据指针
DJNZ R7,STA ;循环发送至结束
RET
;========================================================
;乙机接收程序如下:
; 在进行双机通信时,两机应采用相同的工作方式和波特率。
;=============================================================
MOV SCON,#90H ;设置串行口为方式2,REN为1,允许接收
MOV PCON,#80H ;SMOD=1
MOV R0,#50H ;设置数据块首址
MOV R7,#20 ;置数据块长度
;=========================================================
WAIT:JBC RI,READ ;接收完一帧数据则RI清零并读入数据
AJMP WAIT ;未完等待
;==========================================
READ:MOV A,SBUF ;读入数据
JNB PSW.0,PZ ;收到数为偶数则转
JNB RB8,ERR ;收到数为奇数,发端为偶数则通信出错
SJMP RIGHT ;相符则正确
PZ:JB RB8,ERR ;收到数为偶数,发端为奇数则出错
;========================================
RlGHT:MOV @R0,A ;通信正确,存放数据
INC R0 ;更改地址指针
DJNZ R7,WAIT ;数据块接收完否,未完继续
CLR PSW.5 ;通信正确,置F0为0
RET ;返回
ERROR:SETB PSW.5 ;通信出错,置F0为l
RET ;返回

❺ 请问51单片机与51单片机之间的串口通信程序怎么写

1、查询方式:
#include<reg51.h>
main()
{
unsigned char dat;
TMOD=0x20;
TH1=TL1=0xfd;
SCON=0x50;
TR1=1;
while(1)
{
if(RI)//接收
{
RI=0;
dat=SBUF;
}
SBUF=dat;//发送
while(!TI);
TI=0;
}
}
2、中断方式:
#include<reg51.h>
unsigned char dat;
bit flag;
void uart_isr() interrupt 4
{
if(RI)//接收
{
RI=0;
dat=SBUF;
flag=1;
}
if(TI)TI=0;
}
main()
{
TMOD=0x20;
TH1=TL1=0xfd;
SCON=0x50;
TR1=1;
EA=1;
ES=1;
flag=0;
while(1)
{
if(flag)
{
SBUF=dat;
flag=0;
}
}
}

❻ 51单片机与PC串口通信程序,求指导 ! 具体要求如下:

功能如下:
1、程序烧进去,串口接收显示一个菜单!《如图》A、B、……分别代表一定的功能
例如:A项,代表修改ds1302的时间的数组
2、按照菜单的提示,如:发送A就进入了修改ds1302的时间函数,串口接收界面显
示 A,像图片那种,并显示修改ds1302的操作方法,如从串口发送界面发送
0162115347就表示10年10月16日21时15分34秒星期7,
3、正如第二所说,马上输入1010162115347,就成功的修改了ds1302相关数据,
并返回change success!到串口界面!
4、设置一个功能就是返回主菜单界面。然后又可以就行第二、三步的操作!
5、通过串口,读取单片机里面相关的数据,如时钟的数据
6、说明:可以不要ds1320相关的程序,可以用发光二极管亮来代表修改功能!

❼ 如何实现2个51单片机之间通过串口通信的源程序

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

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 ;0.5 BIT

JNB TF2,$
CLR TF2 ;1 BIT

JNB TF2,$
CLR TF2 ;1.5 BIT
MOV C,UART_RXD
MOV ACC.0,C

JNB TF2,$
CLR TF2

JNB TF2,$
CLR TF2 ;2.5
MOV C,UART_RXD
MOV ACC.1,C

JNB TF2,$
CLR TF2

JNB TF2,$
CLR TF2 ;3.5
MOV C,UART_RXD
MOV ACC.2,C

JNB TF2,$
CLR TF2

JNB TF2,$
CLR TF2 ;4.5
MOV C,UART_RXD
MOV ACC.3,C

JNB TF2,$
CLR TF2

JNB TF2,$
CLR TF2 ;5.5
MOV C,UART_RXD
MOV ACC.4,C

JNB TF2,$
CLR TF2

JNB TF2,$
CLR TF2 ;6.5
MOV C,UART_RXD
MOV ACC.5,C

JNB TF2,$
CLR TF2

JNB TF2,$
CLR TF2 ;7.5
MOV C,UART_RXD
MOV ACC.6,C

JNB TF2,$
CLR TF2

JNB TF2,$
CLR TF2 ;8.5
MOV C,UART_RXD
MOV ACC.7,C

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

POP DPL
POP DPH
POP IE
RET
补充回答:
串口调试

1. 发送:向总线上发命令
2. 接收:从总线接收命令,并分析是地址还是数据。
3. 定时发送:从内存中取数并向主机发送.

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

程序如下:

//这是一个单片机C51串口接收(中断)和发送例程,可以用来测试51单片机的中断接收
//和查询发送,发送没有必要用中断,因为程序的开销是一样的

#include <reg51.h>
#include<stdio.h>
#include <string.h>

#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; //在11.0592MHz下,设置串行口波特率为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的时间,提高效率,

❽ 51单片机的串行口按工作方式1进行串行数据通信,假定波特率为2400b/s编写程序

ORG 0000H
AJMP MAIN ;上电,转向主程序
ORG 0023H ;串行口的中断入口地址
AJMP SERVE ;转向中断服务程序
ORG 0040H ;主程序
MAIN: MOV SP,#60H ;设置堆栈指针
MOV SCON ,#50H
MOV PCON ,#00H
MOV TMOD,#20H
MOV TH1,#0F3H
MOV TL1,#0F3H
SETB TR1
MOV R0 ,#20H ;置发送数据区首地址
MOV R1 ,#40H ;置接收数据区首地址
MOV R7 ,#10H ;置发送字节长度
MOV R6 ,#10H ;置接收字节长度
SETB ES ;允许串行口中断
SETB EA ;CPU允许中断
MOV A ,@R0 ;取第一个数据发送
MOV SBUF ,A ;发送第一个数据
SJMP $ ;等待中断
SERVE: JNB RI ,SEND ;TI=1,为发送中断
CLR RI
MOV A ,SBUF ;读出接收缓冲区内容
MOV @R1 ,A ;读入接收缓冲区
DJNZ R6 ,L1 ;判断数据块发送完否
SJMP L2 ;数据块接收完,转L2
L1:INC R1 ;修改数据区指针
L2:RETI ;中断返回
SEND:
CLR TI ;清除发送中断标志
DJNZ R7 ,L3 ;判断数据块发送完否
SJMP L4 ;数据块接收完,转L4
L3: MOV A ,@R0 ;取数据发送
MOV SBUF ,A ;发送数据
INC R0 ;修改数据地址
L4:
RETI ;中断返回
END

❾ 51单片机的串行通信

这个是单片机用18b20采集温度,传给电脑的程序;电脑那端用VB里的串口控件就能捕获了,你可以吧里面发送出去的数据换成你采集的 你想加我的qq也行
-----------------------------------------
#include <AT89X51.H>
#include <intrins.h>
#define Key_UP P1_0
#define Key_DOWN P1_1
#define Key_SET P1_2
#define RelayOutPort P2_0
#define LEDPort P0
#define DELPort P2_1
#define LEDTwoC P3_6
#define LEDThreeC P3_7
#define TMPort P2_7
#define INBUF_LEN 5 //数据长度
unsigned char inbuf1[INBUF_LEN]={'0','0','0','0','0'};//发送缓冲区
unsigned char inbuf2[50];//接收缓冲区
unsigned char count3;
void init_serialcomm( void )
{
SCON = 0x50 ; //SCON: serail mode 1, 8-bit UART, enable ucvr
TMOD |= 0x20 ; //TMOD: timer 1, mode 2, 8-bit reload
PCON |= 0x80 ; //SMOD=1;
TH1 = 0xFA ; //Baud:4800 fosc=11.0592MHz
IE |= 0x90 ; //Enable Serial Interrupt
TR1 = 1 ; // timer 1 run
}
//向串口发送一个字符
void send_char_com( unsigned char ch)
{
SBUF=ch;
while (TI== 0 );
TI= 0 ;
}
//向串口发送一个字符串,strlen 为该字符串长度
void send_string_com( unsigned char *str, unsigned int strlen)
{
unsigned int k= 0 ;
do
{
send_char_com(*(str + k));
k++;
} while (k < strlen);
}
//串口接收中断函数
void serial () interrupt 4 using 3
{
if (RI) //RI==开始接收
{
unsigned char ch;
RI = 0 ; //软件RI=0
ch=SBUF;
if (ch> 1 )
{
count3= 0 ;
inbuf2[count3]=ch;
}
else
{
count3++;
inbuf2[count3]=ch;
}
}
} unsigned char code LEDDis[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF,0xBF}; //0-9的LED笔划,0xFF为空,0xF7为负号
unsigned char dis_8[12]={'0','1','2','3','4','5','6','7','8','9',' ','-'};
static unsigned char bdata StateREG; //可位寻址的状态寄存器
sbit DS1820ON = StateREG^0; //DS1820是否存在
sbit SetTF = StateREG^1; //是否是在温度设置状态
sbit KeySETDown = StateREG^2; //是否已按过SET键标识
sbit PowTF = StateREG^3; //电源电源标识
sbit KeyTF = StateREG^4; //键盘是否允许//sbit KeySETDowning = StateREG^5; //SET是否正在按下
static unsigned char bdata TLV _at_ 0x0029; //温度变量高低位
static unsigned char bdata THV _at_ 0x0028;
static signed char TMV; //转换后的温度值
static unsigned char KeyV,TempKeyV; //键值
static unsigned char Second;
static unsigned char flag;
static signed char TMRomV _at_ 0x0027; //高温限制
static signed char TMSetV _at_ 0x0026; //温度设定值
static unsigned char KSDNum; //SET键连按时的采集次数
static unsigned char IntNum,IntNum2,IntNum3; //中断发生次数,IntNum用于SET长按检测,IntNum2用于设定状态时LED闪烁
static signed char LED_One,LED_Two,LED_Three; //LED的显示位 LED_One为十位,LED_Two为个位
static unsigned char Sign; //负号标识void main(void)
{ void InitDS1820(void); //定义函数
void ROMDS1820(void);
void TMVDS1820(void);
void TMRDS1820(void);
void TMWDS1820(void);
void TMREDS1820(void);
void TMERDS1820(void);
void ReadDS1820(void);
void WriteDS1820(void);
void Delay_510(void);
void Delay_110(void);
void Delay_10ms(void);
void Delay_4s(void);
void V2ToV(void);

DELPort=1;
StateREG = 0; //初始化变量
SetTF = 0;
PowTF = 0; //关电源
THV = 0;
TLV = 0;
TMV = 0;
KeyV = 0;
TempKeyV = 0;
KSDNum = 0;
IntNum = 0;
IntNum2 = 0;
IntNum3 = 0;
LED_One = 0;
LED_Two = 0; InitDS1820(); //初始化
ROMDS1820(); //跳过ROM
TMERDS1820(); //E2PRAM中温度上限值调入RAM
InitDS1820(); //初始化
ROMDS1820(); //跳过ROM
TMRDS1820(); //读出温度指令
ReadDS1820(); //读出温度值和上限值
TMSetV = TMRomV; //拷贝保存在DS18B20ROM里的上限值到TMSetV EA = 1; //允许CPU中断
ET0 = 1; //定时器0中断打开
TMOD = 0x1; //设定时器0为模式1,16位模式
TH0=0xB1;
TL0=0xDF; //设定时值为20000us(20ms)
TR0 = 1;

while(1){ //开始定时
if (flag==0){
if (Second==1){
Delay_4s();
Delay_4s();
Delay_4s();
Delay_4s();
Delay_4s();
Delay_4s();

DELPort=0;
Second=0;
}
}
}

}//定时器0中断外理中键扫描和显示
void KeyAndDis_Time0(void) interrupt 1 using 2
{
TH0=0xB1;
TL0=0xDF; //设定时值为20000us(20ms) LEDPort = 0xFF;

if (inbuf2[0]==0x33){
send_char_com('O');
send_char_com('O');
send_char_com('O');
SetTF = 1;
//send_string_com(inbuf2,1);
//BEEP=0;
//RELAY=0;
send_char_com('O');
//inbuf2[0]=0x00;
inbuf2[0]=0x00;
} if (inbuf2[0]==0x36){//send_string_com(inbuf2,1);
//BEEP=1;
send_char_com('N');
send_char_com('N');
send_char_com('N');
SetTF = 0;inbuf2[0]=0x00;} if (inbuf2[0]==0x34){
KeyV=2;
//send_string_com(inbuf2,1);
//BEEP=0;
//RELAY=0;
TMSetV = TMSetV - 1;
inbuf2[0]=0x00;
} if (inbuf2[0]==0x35){//send_string_com(inbuf2,1);
//BEEP=1;
//RELAY=1;
TMSetV = TMSetV + 1; //上调温度
inbuf2[0]=0x00;
} if (inbuf2[0]==0x74){
KeyV=2;
//send_string_com(inbuf2,1);
//BEEP=1;
//RELAY=1;
} if (inbuf2[0]==0x90){
KeyV=1;
//send_string_com(inbuf2,1);
//BEEP=1;
//RELAY=1;
}
if (!Key_UP)
KeyV = 1;
if (!Key_DOWN)
KeyV = 2;
if (!Key_SET)
KeyV = 3;
//KeySETDowning = 0; //清除
if (KeyV != 0) //有键按下
{
Delay_10ms(); //延时防抖 按下10ms再测
if (!Key_UP)
TempKeyV = 1;
if (!Key_DOWN)
TempKeyV = 2;
if (!Key_SET)
TempKeyV = 3;
if (KeyV == TempKeyV) //两次值相等为确定接下了键
{
if (KeyV == 3) //按下SET键,如在SET状态就退出,否则进入
{
//KeySETDowning = 1; //表明SET正在按下

PowTF = 0; //电源标识开
if (!KeyTF)
if (SetTF){
send_char_com('N');
send_char_com('N');
send_char_com('N');
SetTF = 0; //标识位标识退出设定

InitDS1820(); //初始化
ROMDS1820(); //跳过ROM
TMWDS1820(); //写温度上限指令
WriteDS1820(); //写温度上限到DS18B20ROM
WriteDS1820(); //写温度上限到DS18B20ROM
WriteDS1820(); //写温度上限到DS18B20ROM
InitDS1820(); //初始化
ROMDS1820(); //跳过ROM
TMREDS1820(); //温度上限值COPY回E2PRAM
}
else {
send_char_com('O');
send_char_com('O');
send_char_com('O');
SetTF = 1;}

if (!KeySETDown) //没有第一次按下SET时,KeySETDown标识置1
KeySETDown = 1;
else
KSDNum = KSDNum + 1; //前一秒内有按过SET则开始计数
}
if (SetTF) //在SET状态下
{

if ((KeyV == 1) && (!KeyTF))
TMSetV = TMSetV + 1; //上调温度
if ((KeyV == 2) && (!KeyTF))
TMSetV = TMSetV - 1; //下调温度
if (TMSetV <= 20) //限制温度上下限
TMSetV = 20;
if (TMSetV >= 75)
TMSetV = 75;
}
if ((!KeyTF) && (IntNum3 == 0)) KeyTF = 1; //当键盘处于可用时,锁定
}
}
KeyV = 0;
TempKeyV = 0; //清空变量准备下次键扫描 if (!PowTF)
{
InitDS1820(); //初始化
ROMDS1820(); //跳过ROM
TMVDS1820(); //温度转换指令 Delay_510();
Delay_510(); //延时等待转换完成 InitDS1820(); //初始化
ROMDS1820(); //跳过ROM
TMRDS1820(); //读出温度指令
ReadDS1820(); //读出温度值 V2ToV(); //转换显示值
if (TMV > TMSetV) //根据采集到的温度值控制继电器
{
RelayOutPort = 0;
flag=0;
}
else
{
RelayOutPort = 1;
DELPort=1;
Second=1;
flag=1;
} if (SetTF) IntNum2 = IntNum2 + 1; //用于闪烁计数
if (IntNum2 > 50 ) IntNum2 = 0;
if (KeyTF) IntNum3 = IntNum3 + 1; //用于防止按键连按
if (IntNum3 > 25)
{
IntNum3 = 0;
KeyTF = 0;
} if ((SetTF) && (IntNum2 < 25)) goto InitEnd; //计数在后半段时显示

LEDPort = LED_Two;
LEDTwoC = 0;
Delay_510();
LEDTwoC = 1; //显示十位数
LEDPort = LED_Three;
LEDThreeC = 0;
Delay_510();
LEDThreeC = 1; //显示个位数
}
InitEnd:;
}void V2ToV(void) //数值转换
{
TLV = TLV >> 4;
THV = THV << 4; //读出的高低位数值移位
TMV = TLV | THV; //合并高低位放入TM为实际温度值
Sign = 0;
if (SetTF || !Key_SET)
Sign = TMSetV >> 7; //取符号
else
Sign = TMV >> 7; if (Sign)
{
if (SetTF || !Key_SET)
{
LED_One = (~(TMSetV-1)) / 100; //SET状态下显示设定值
LED_Two = ((~(TMSetV-1)) - LED_One * 100)/10;
LED_Three = (~(TMSetV-1)) - LED_One * 100 - LED_Two * 10;
inbuf1[0]=dis_8[LED_Two];
inbuf1[1]=dis_8[LED_Three];
//inbuf1[2]=dis_8[ LED_Three];
inbuf1[2]=0x0d;
inbuf1[3]=0x0a;
}
else
{
LED_One = (~(TMV-1)) / 100; //转换百位值
LED_Two = ((~(TMV-1)) - LED_One * 100)/10;
LED_Three = (~(TMV-1)) - LED_One * 100 - LED_Two * 10;
inbuf1[0]=dis_8[LED_Two];
inbuf1[1]=dis_8[LED_Three];
inbuf1[2]=dis_8[0];
inbuf1[3]=0x0d;
inbuf1[4]=0x0a;
}
}
else
{
if (SetTF || !Key_SET)
{
LED_One = (TMSetV) / 100; //SET状态下显示设定值
LED_Two = (TMSetV - LED_One * 100)/10;
LED_Three = TMSetV - LED_One * 100 - LED_Two * 10;
inbuf1[0]=dis_8[LED_Two];
inbuf1[1]=dis_8[LED_Three];
inbuf1[2]=dis_8[0];
inbuf1[3]=0x0d;
inbuf1[4]=0x0a;
}
else
{
LED_One = (TMV) / 100; //转换百位值
LED_Two = (TMV - LED_One * 100)/10;
LED_Three = TMV - LED_One * 100 - LED_Two * 10;
inbuf1[0]=dis_8[LED_Two];
inbuf1[1]=dis_8[LED_Three];
inbuf1[2]=dis_8[0];
inbuf1[3]=0x0d;
inbuf1[4]=0x0a;
}
} init_serialcomm(); //初始化串口//while ( 1 )
//{
send_string_com(inbuf1,INBUF_LEN); //转LED字段
if (LED_One) //超过百时十位的处理
LED_Two = LEDDis[LED_Two];
else
{
if (LED_Two == 0)
LED_Two = LEDDis[10];
else
LED_Two = LEDDis[LED_Two];
}
if (Sign)
LED_One = LEDDis[11];
else
{
if (LED_One == 0)
LED_One = LEDDis[10];
else
LED_One = LEDDis[LED_One];
}
LED_Three = LEDDis[LED_Three];
}void InitDS1820(void) //初始化DS1820
{

}void ROMDS1820(void) //跳过ROM匹配
{}void TMVDS1820(void) //温度转换指令
{}void TMRDS1820(void) //读出温度指令
{}void TMWDS1820(void) //写入温度限制指令
{}void TMREDS1820(void) //COPY RAM to E2PRAM
{}void WriteDS1820(void) //写入温度限制值
{
}void ReadDS1820(void) //读出温度值
{}void Delay_510(void) //延时510微秒
{
}void Delay_10ms(void) //延时10ms
{
}void Delay_4s(void) //延时4s
{}

❿ C51单片机:设计一个串行通信程序,波特率为1200b/s,发送数据I Love U Forever

#include <reg51.h>
//晶振=12M
void InitUART(void)
{
TMOD = 0x20;
SCON = 0x40;
TH1 = 0xE6;
TL1 = TH1;
PCON = 0x00;
TR1 = 1;
}

void SendString(unsigned char *c)
{
while(*c)
{
SBUF = *c++;
while(!TI);
TI = 0;
}
}

void main(void)
{
InitUART();
SendString("I Love U Forever");
while(1);
}

阅读全文

与51单片机单机串行通信程序相关的资料

热点内容
自己购买云主服务器推荐 浏览:419
个人所得税java 浏览:761
多余的服务器滑道还有什么用 浏览:189
pdf劈开合并 浏览:28
不能修改的pdf 浏览:752
同城公众源码 浏览:488
一个服务器2个端口怎么映射 浏览:297
java字符串ascii码 浏览:78
台湾云服务器怎么租服务器 浏览:475
旅游手机网站源码 浏览:332
android关联表 浏览:945
安卓导航无声音怎么维修 浏览:332
app怎么装视频 浏览:430
安卓系统下的软件怎么移到桌面 浏览:96
windows拷贝到linux 浏览:772
mdr软件解压和别人不一样 浏览:904
单片机串行通信有什么好处 浏览:340
游戏开发程序员书籍 浏览:860
pdf中图片修改 浏览:288
汇编编译后 浏览:491