串口通信实验报告

时间:2024.4.2

 

单片机实验报告

      课程名称       单片机技术与应用      

       实验名称           串口通信实验          

       专    业           光电信息工程           

       班    级           光电121            

       学    号              050312113             

       姓    名              蒯玄                

      实验地点         躬行楼528           

      实验日期          2015.5.28            


一、实验目的

1、掌握8051单片机串行口工作原理;

2、掌握串口编程与调试方法;

3、了解Modbus协议及其应用;

4、了解数据传输的可靠性措施与CRC校验实现方法;

5、掌握8051单片机的Modbus编程;

二、实验仪器

三、实验内容

       串口功能验证:PC机与8051单片机通信实验:若PC机发送数据a,则单片机接收a后向PC机发送a+1;用串口工具软件(sscom32)观察通信结果。

       设计思路: PC机采用主动方式,单片机为被动方式,因单片机端不知道PC何时发数据,若单片机采用查询方式接收,会产生接收不到PC数据而“死等”的现象。因此为了不影响单片机端的主程序运行,单片机应采用中断方式接收;

       参考源码:

//中断服务程序 

unsigned char Rxd_Data;//串口接收数据

unsigned char Rxd_Over;//串口接收完成标志

//串口初始化函数9600bps

void Sbuf_Init(void)

{

    SCON=0x50;  //10位方式

    //波特率设置

    PCON=0x00;  //波特率不倍增

    TMOD=(TMOD&0x0f)|0x20;//T1方式2

    TH1=0xfd;       //T1计数初值

    TL1=0xfd;

    ES=1;EA=1;   //串口中断使能

    TR1=1;            //启动定时器

void UART_ISR(void) interrupt 4

{

    if(RI)//接收产生的中断

    {

           RI=0;//清接收标志

           Rxd_Data=SBUF; //接收数据

           Rxd_Over=1;  //置Rxd_Over标志             

    }

}

void main(void)

{

    Sbuf_Init();          //串口初始化

    while(1)

    {

           if(Rxd_Over)    //若接收完成

           {

                  //串口数据发送

                  SBUF=a+1;   //串口发送

                  while(TI==0); //等待发送完成

                  TI=0;//清发送标志

                  Rxd_Over=0;   //清Rxd_Over标志

           }

    }

}

利用此程序可以判断串口通信是否正常。串口通信失败的原因有如下几种情况:

(1)串口线未连接,用一根导线将串口线2,3脚短接,scomm32工具发送数据,根据能否接收数据判断串口线连接是否正常;

(2)最小系统板硬件故障:借助示波器观察单片机的串口接收与发送CMOS电平与RS232电平可排查硬件故障;

(3)软件问题。

四、预习要求

    完成实验源码的预编写。

五、实验步骤

    使用串口前,应对它进行初始化。

    设置串行口工作方式控制(SCON);

    设置串口通信波特率:T1(TMOD、TH1、TL1、ET1、EA、TR1 、PCON);

    串口中断使能(ES、EA)。具体步骤如下:

(1)设置串行口工作方式控制(SCON)

如11位波特率可变的异步通信方式:

SCON=0xd0;(11010000)

(2)借助T1初使化通信波特率(TMOD)

Baud=2^SMOD×(T1溢出率/32)

令SMOD=0,则9600=1/(n*12/fosc*32) ,若fosc=11.0592则n=3

T1:采用方式2(8位自动载入)

即:PCON=0x00;

    TMOD=(TMOD&0x0f)|0x20;

    TH1=0xfd;

    TL1=0xfd;

    TR1=1;

六、实验过程

程序部分:

#include "reg51.h"

#include "crc16.h"

#define MODBUS_ADDR   0x01

#define MODBUS_RD     0x03

#define MODBUS_WDATA1 0x02

unsigned char RxD_buf[8],TxD_buf[8];

unsigned char RX_OVER; //全局变量:1:串口接收完成标志

//////////////////////////////////////////////////////

////// 中断服务程序///////////////////////////////////

//////////////////////////////////////////////////////

void UART_ISR(void) interrupt 4                  

{

   static unsigned char count=0;

   static unsigned char pre_data=0;

   static unsigned char mid_data=0;

   static unsigned char now_data=0;

   //////////////////////////////////////////////

   if(RI)

   {

       now_data=SBUF;

       if(pre_data==MODBUS_ADDR && mid_data==MODBUS_RD  && now_data==MODBUS_WDATA1)

       {

          RxD_buf[0] = pre_data;

          RxD_buf[1] = mid_data;

          RxD_buf[2] = now_data;

          count=3;

       }

       else

       {

          RxD_buf[count] = now_data;

          count++;

          if(count==8)

          {

              count=0;

              RX_OVER=1; //置接收完成标志

          }

       }

       pre_data = mid_data;

       mid_data = now_data;   

       RI=0;

   }

}

//////////////////////////////////////////////////////

////////串口初始化函数:波特率为9600bps////////////////

//////////////////////////////////////////////////////

void Sbuf_Init(void)

{

    SCON=0x50;  //10位方式

   //波特率设置

   PCON=0x00;  //波特率不倍增

    TMOD=(TMOD&0x0f)|0x20;//T1方式2

    TH1=0xfd;    //T1计数初值

    TL1=0xfd;

   ES=1;EA=1; //串口中断使能

    TR1=1;       //启动定时器

}

      

//////////////////////////////////////////////////////

//////主程序//////////////////////////////////////////

//////////////////////////////////////////////////////

void main(void)

{

   unsigned short int crc_value;

   //串口初始化函数调用

   unsigned int i;

  

   while(1)

   {

       if(RX_OVER)     //若接收完成

       {

          //先求CRC16校验

          crc_value=CRC16_C(RxD_buf,6); //对接收到的前6个字节求CRC16校验

          //低字节在前,高字节在后

          if((crc_value%256)==TxD_buf[6] && crc_value/256==TxD_buf[7])

          {

              //CRC16校验成功

              //回传:字节1 字节2  字节3  字节4  字节5  字节6  字节7  字节8

              //      0x01  0x03  0x02  a+1   数据2  0(成功)CRC16_L CRC16_H

              //此处添加TxD_buf[0]~TxD_buf[5]赋值,计算CRC16,串口查询方式发送代码

              TxD_buf[0] = 0x01;

              TxD_buf[1] = 0x03;

              TxD_buf[2] = 0x02;

              TxD_buf[3] = RxD_buf[3]+1;

              TxD_buf[4] = 0x00;

              TxD_buf[5] = 0x00;

              crc_value = CRC16_C(RxD_buf,6);

              TxD_buf[6] = crc_value%256;

              TxD_buf[7] = crc_value/256;

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

              {

                 SBUF = TxD_buf[i];

                 while(TI==0);

                 TI = 0;

              }

          }

          else

          {

              //CRC校验失败

              //回传:字节1 字节2  字节3  字节4  字节5  字节6     字节7 字节8

              //      0x01  0x03  0x02  *     数据2  0xff(成功)CRC16_L  CRC16_H

              //此处添加TxD_buf[0]~TxD_buf[5]赋值,计算CRC16,串口查询方式发送代码

              TxD_buf[0] = 0x01;

              TxD_buf[1] = 0x03;

              TxD_buf[2] = 0x02;

              TxD_buf[3] = RxD_buf[3];

              TxD_buf[4] = 0x00;

              TxD_buf[5] = 0xff;

              crc_value = CRC16_C(RxD_buf,6);

              TxD_buf[6] = crc_value%256;

              TxD_buf[7] = crc_value/256;

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

              {

                 SBUF = TxD_buf[i];

                 while(TI==0);

                 TI = 0;

              }     

             

          }

           RX_OVER=0;   //清接收完成标志,避免多次执行

       }

   }

}

运行结果:

                     正确串口输出

   

                  错误串口输出

七、实验小结

       通过此次实验,我们了解到单片机的工作原理,以及串口通信的工作方式,加深了对单片机的掌握。利用单片机进行串口的连接,输入与输出。编写程序,实现加一功能,当输入错误时,串口输出FF,当输入正确时,输出自动加一,并且显示输出00,表示输入的结果是正确的。这样就实现了串口之间的连接与信息的传递。掌握8051单片机串行口工作原理,掌握串口编程与调试方法,了解Modbus协议及其应用,了解数据传输的可靠性措施与CRC校验实现方法,掌握8051单片机的Modbus编程,本次试验我们学到的有很多,试验相对来说较为简单,能够独立完成。本次实验过程中还运用到一个新的校验软件,操作起来并没有什么难度,而且还能很准确的校验出我们的结果是否正确,既方便又快捷。

   

 

 

 

 

 

 


第二篇:uart串口通信实验报告


串口通信实验报告

基本实验:16位的乘法器

设计思想:乘法器根据以往学过数电的设计经验,应该是移位相加的方法,设被乘数为[15:0]a,乘数为[15:0]b,则从b的最高位开始算起,c初值为0,为b最高位为1,则c就等于c+a;接下来,若b的次高位为1,则c左移一位加a,若为0则c左移一位就可以了,这样的步骤做到b的最低位那么c的值就是a*b,当然最好c是中间寄存器,这样结果才不会出现中间值。

实验的源码:

module muti(clk,rst,ready,a,b,c);

    input clk;

    input rst;

    input [15:0]a;

    input [15:0]b;

    output [31:0]c;

    output ready;

    reg    [31:0]c;

    reg    ready;

    reg    [31:0]temp;

    reg   [5:0]n;

    always @(posedge clk or posedge rst)

    begin

    if(rst)

     begin

      c<=0;

      ready<=1;

      temp<=0;

      n<=32;

     end

    else

    if(ready)

     begin

     temp<=0;

     n<=32;

     ready<=0;

     end

    else

    if(n)

      begin

      if(b[n-1])

       begin

       temp<=(temp<<1)+a;

       n<=n-1;  

       end

      else

      begin

      temp<=temp<<1;

      n<=n-1;

      end

       end

    else

    begin

    c<=temp;

    n<=32;

    ready<=1;

    end

end

endmodul

测试代码:

`timescale 1ns/1ns

module tb;

    reg clk;

    reg [15:0]a;

    reg [15:0]b;

    reg rst;

    wire ready;

    wire [31:0]c;

always #10 clk=~clk;

initial

begin

rst<=1;

clk<=0;

a=0;

b=0;

#10 rst=0;

#21 a=21;b=32;

#650 a=3;b=4;

#700 $stop;

end

muti muti_unit(

.a(a),

.b(b),

.rst(rst),

.clk(clk),

.ready(ready),

.c(c));

endmodule

仿真结果:

这边a被乘数,b是乘数,当rst为高时,则将c置0,ready置一,ready信号为高表示此时空闲可以计算,rst为低时则开始计算,21*32为672,3*4为12,在乘法操作时,ready信号为低电平表示在工作中不能再输入进行计算,当 计算结束则变为高电平。乘法功能得以实现。

进阶实验:串口通信实验

基本要求:了解UART 串口通信协议

设计思想:主要是分成3个模块,一个是波特率产生模块,一个是发送模块,一个是接收模块,波特率产生模块产生一个9600Hz的采样脉冲,由于开发板上的固有频率为50MHz,所以我需要分频为50000000/9600=5208.3,即从0记到5207,当记到2503时产生一个时钟周期的高电平即可。发送模块受到接受模块的控制,接收模块的输出RXD连发送的TXD,RXD为高表示正在接收不能发送数据,发送时采用并转串发送,接收时为串转并接收。

实验代码:

1. top文件

module top(F50M,rst,datain,dataout,seg);

input  F50M;/////50MHz的时钟信号

input  rst;///////////////复位信号

input  [7:0]datain;///////////输入数据

output [7:0]dataout;////////////////输出数据

output [3:0]seg;/////////////////板子上面选一个led

wire  bps_start1;/////////////////当正在发送时为高电平

wire  bps_start2;///////////////正在接收时为高电平

wire  caiyang1;//////////////////////采样的波特率信号

wire  caiyang2;

wire  RXD_TXD;

wire  dataout;

wire  rx232_tx;///////////////////////中间的串行通信线

brate1 brate1(

.F50M(F50M),

.rst(rst),

.bps_start1(bps_start1),

.caiyang1(caiyang1)

);

brate2 brate2(

.F50M(F50M),

.rst(rst),

.bps_start2(bps_start2),

.caiyang2(caiyang2)

);

rev rev_u(

.F50M(F50M),

.rx232_tx(rx232_tx),

.rst(rst),

.caiyang2(caiyang2),

.RXD(RXD_TXD),

.dataout(dataout),

.bps_start2(bps_start2)

         );

send send_u(

.F50M(F50M),

.datain(datain),

.rst(rst),

.caiyang1(caiyang1),

.TXD(RXD_TXD),

.bps_start1(bps_start1),

.rx232_tx(rx232_tx)

);

seg seg_u(.F50M(F50M),

.seg(seg));

endmodule

波特率产生模块:

A.发送波特率产生模块:

module brate1( F50M,rst,bps_start1,caiyang1);

input  F50M;

input  rst;

input  bps_start1;

               

output caiyang1;

reg    [12:0]n;//50MHz/9600hz=5208,n  count  0 to 5207

reg    caiyang1;//a 9600 bound rate sign

always @(posedge F50M or negedge rst)

begin

if(!rst)

begin

n<=0;

caiyang1<=0;

end

else

if((n==5207) || !bps_start1) ////////////如果记满5207或者发送数据结束就将caiyang2清0

begin

n<=0;

caiyang1<=0;

end

else

if(n==2603)//////////////////////////////计数满2603就产生一个时钟周期的高电平

begin

n<=n+1;

caiyang1<=1;

end

else

begin

n<=n+1;

caiyang1<=0;

end

end

endmodule

B.接收波特率产生模块

module brate2( F50M,rst,bps_start2,caiyang2);

input  F50M;

input  rst;

input  bps_start2;

output caiyang2;

reg    [12:0]n;//50MHz/9600hz=5208,n  count  0 to 5207

reg    caiyang2;//a 9600 bound rate sign

always @(posedge F50M or negedge rst)

begin

if(!rst)

begin

n<=0;

caiyang2<=0;

end

else

if((n==5207) || !bps_start2)////////////如果记满5207或者发送数据结束就将caiyang2清0

begin

n<=0;

caiyang2<=0;

end

else

if(n==2603)

begin

n<=n+1;

caiyang2<=1;

end

else

begin

n<=n+1;

caiyang2<=0;

end

end

endmodule

发送模块:

module send(F50M,datain,caiyang1,TXD,rst,bps_start1,rx232_tx);

input F50M;

input [7:0]datain;////输入要发送的数据

input rst;       

input caiyang1;   

input TXD;  /////接收接收端的状态数据,若收到为1,表示接收端正在接收不能发送数据,采样其下降沿作为发送模块的启动时间点

     

output bps_start1;

output rx232_tx; 输出一个串行数据

 

reg   rx232_tx;

reg   bps_start1;

reg   a;

reg   b;

reg   c;

wire  neg_TXD;

////////////////////////////////////////////

//////捕捉TXD下降沿表示可以开始发送数据,

always @ (posedge F50M or negedge rst)

begin

if(!rst)

begin

a<=1;

b<=1;

end

else

begin

b<=a;

a<=TXD;

end

end

assign neg_TXD=~a&b;

////////////////////////////////////////////////

/////////将状态置位和发送信号

reg  [4:0]n;

reg txd_en;          

reg [7:0]temp_data; 

always @ (posedge F50M or negedge rst)

begin

if(!rst)

begin

n<=0;

bps_start1<=0;

txd_en<=0;

temp_data<=0;

rx232_tx<=1;

end

else

if(neg_TXD)

begin

txd_en<=1;

bps_start1<=1;

temp_data<=datain;

end

else

if(n==12) /////////////////记到12表示发送结束,将所有状态重置

begin

txd_en<=0;

bps_start1<=0;

n<=0;

end

else

if(txd_en)//////////////////发送使能,内部的一个使能信号

begin

if(caiyang1)///////////////采样波特率

begin

case(n)

4'd0: begin rx232_tx<=0;n<=n+1; end////////加起始位0

4'd1: begin rx232_tx<=temp_data[0];n<=n+1; end////1到8为数据位

4'd2: begin rx232_tx<=temp_data[1];n<=n+1; end

4'd3: begin rx232_tx<=temp_data[2];n<=n+1; end

4'd4: begin rx232_tx<=temp_data[3];n<=n+1; end

4'd5: begin rx232_tx<=temp_data[4];n<=n+1; end

4'd6: begin rx232_tx<=temp_data[5];n<=n+1; end

4'd7: begin rx232_tx<=temp_data[6];n<=n+1; end

4'd8: begin rx232_tx<=temp_data[7];n<=n+1; end

4'd9: begin rx232_tx<=1;n<=n+1; end////////////加奇偶校验位

4'd10: begin rx232_tx<=1;n<=n+1; end///////////////截止位

default: begin  rx232_tx<=1;n<=n+1; end/////////其余时候均为1

endcase

end

end

end

endmodule

接收模块:

module rev(F50M,rx232_tx,rst,caiyang2,RXD,dataout,bps_start2);

input F50M;

input rx232_tx;////////发送过来的串行数据

input rst;

input caiyang2;

output RXD;////////////当正在接收时,RXD为1,接收完毕产生一个周期低电平表示接受完,连接发送端的TXD输入

output [7:0]dataout;

output bps_start2;

reg   RXD;

reg   [7:0]dataout;

reg   bps_start2;

//////////////捕捉rx232_tx的下降沿

reg a;

reg b;

wire neg_rx232;

always @ (posedge F50M or negedge rst)

begin

if(!rst)

begin

a<=1;

b<=1;

end

else

begin

b<=a;

a<=rx232_tx;

end

end

assign neg_rx232=~a&b;////////////////捕捉到下降沿时置1

/////////////////////////////////////////////////////////

/////////////标志位置位和串转并从数据线到接收端的寄存器

reg [7:0]temp;

reg [3:0]n;

reg rxd_en;

always @(posedge F50M or negedge rst)

begin

if(!rst)

begin

n<=0;

dataout<=0;

RXD<=0;

bps_start2<=0;

rxd_en<=0;

temp<=0;///////////////////////复位信号

end

else

if(n==12)////////////当计数到12的时候表示已经接受完毕,将状态全部初始到未传时

begin

n<=0;

rxd_en<=0;

RXD<=0;

bps_start2<=0;

dataout<=temp;

end

else

if(neg_rx232)/////////////////如果捕捉到了信号的下降沿,表示得到了起始位0,则将状态置一表示启动接收

begin

bps_start2<=1;

RXD<=1;

rxd_en<=1;

end

else

if(rxd_en)//////////////////接收使能

begin

if(caiyang2)/////////////////按照9600波特率采样

begin

if(n!=12)

begin

case(n)

4'd1: begin temp[0]<=rx232_tx;n<=n+1; end //////从第二位开始接收数据

4'd2: begin temp[1]<=rx232_tx;n<=n+1; end

4'd3: begin temp[2]<=rx232_tx;n<=n+1; end

4'd4: begin temp[3]<=rx232_tx;n<=n+1; end

4'd5: begin temp[4]<=rx232_tx;n<=n+1; end

4'd6: begin temp[5]<=rx232_tx;n<=n+1; end

4'd7: begin temp[6]<=rx232_tx;n<=n+1; end

4'd8: begin temp[7]<=rx232_tx;n<=n+1; end

default:n<=n+1;///////////////////////////////////其余时刻不置位

endcase

end

end

end

end

endmodule

定义了一个seg模块用来选择哪个led

module seg(F50M,seg);

input F50M;

output [3:0]seg;

reg [3:0]seg;

always @ (posedge F50M)

begin

seg<=4'b0111;

end

endmodule

约束条件

NET"F50M" LOC="B8";

NET"rst" LOC="H13";

NET"datain[0]" LOC="R17";

NET"datain[1]" LOC="N17";

NET"datain[2]" LOC="L13";

NET"datain[3]" LOC="L14";

NET"datain[4]" LOC="K17";

NET"datain[5]" LOC="K18";

NET"datain[6]" LOC="H18";

NET"datain[7]" LOC="G18";

NET"dataout[0]" LOC="L18";

NET"dataout[1]" LOC="F18";

NET"dataout[2]" LOC="D17";

NET"dataout[3]" LOC="D16";

NET"dataout[4]" LOC="G14";

NET"dataout[5]" LOC="J17";

NET"dataout[6]" LOC="H14";

NET"dataout[7]" LOC="C17";

NET"seg[0]" LOC="F17";

NET"seg[1]" LOC="H17";

NET"seg[2]" LOC="C18";

NET"seg[3]" LOC="F15";

modsim上面的仿真结果:

从图上可以看出一开始就有两个数据需要传输,一个是13,一个是45,则在下一个周期,发送模块的内部寄存器置为13,一直到发送模块将13全部发出,这个时候内部寄存器才接受45,这是接收模块检测到数据线上有一个下降沿,既检测到起始位0,则开始工作接受13,等到接受完13,则RXD变为低电平,发送端继续发送下一个数据45.

Ise验证

烧到板子上进行验证,由于没有办法进行电脑和板子之间的通信,我把发送的datain置为8个开关,dataout连置一个led灯。复位为H13。

当rst没有按下为低电平时,则dataout为全高,即LED灯全亮,当将K17,K18推高,即datain的第5,6位置高则显示3.,和下面的只将R17,N17,L13置低则显示7,这些基本说明串行通信基本算是成功的。

更多相关推荐:
串口通信实验报告

基于Labview的串行通信接口实验报告一实验目的通过软件Labview编写前面板和程序框图通过该面板实现计算机与外围设备的串口通信设置好通信端口波特率等参数后在输入控件中输入数据字符当点击发送按钮时下位机发生...

单片机串口通讯实验报告

实验十单片机串行口与PC机通讯实验报告实验目的1掌握串行口工作方式的程序设计掌握单片机通讯的编制2了解实现串行通讯的硬环境数据格式的协议数据交换的协议3了解PC机通讯的基本要求实验器材1G6W仿真器2MCS51...

基于VC++ 6.0的串口通信实验报告

网络与通信实验报告网络与通信实验报告题目串口通行实验班级0309103学号030910338姓名田静指导老师付大丰日期20xx1021网络与通信实验报告一实验要求把两台计算机的串口通过串口线连在一起通过串口实现...

串口通信实验报告

基于LabwindowsCVI的串行通信接口实验报告一实验目的通过软件LabwindowsCVI编写仪器面板通过该面板实现计算机与外围设备的串口通信设置好通信端口波特率等参数后在TextBox控件中输入数据字符...

rs232串口通信实验报告

计算机网络实验实现RS232串口通信程序及MODBUS协议的编程一实验目的1熟悉并掌握RS232串口标准及原理2实现PC机通过RS232串口进行数据的收发3掌握MODBUS协议4掌握MODBUS协议编程的编写二...

嵌入式ARM串口实验报告

实验五串口通信实验1实验目的1掌握ARM的串行口工作原理2编程实现ARM的UART通讯3掌握S3C2410寄存器配置方法2实验设备1S3C2410嵌入式开发板JTAG仿真器2软件PC机操作系统WindowsXP...

串口通信实验报告

华南农业大学实验报告目录1实验任务和目的12实验准备13实验步骤14实验分析与总结11分析12总结31实验任务和目的了解串行通信的背景知识后通过三线制制作一条串口通信线PCPC并编程实现两台PC间通过RS232...

单片机与PC机串口通信实验报告

单片机与PC机串口通讯学生何绍金学号专业班级自动化1202指导老师杨东勇20xx年12月一实验目的学习PC机的串口通讯原理二实验设备统一电子开发平台三实验要求单片机与电脑串口通讯将单片机与电脑相连借助串口调试助...

RS232串口通信实验报告

RS232串口通信实验报告学号学院电子信息学院班级08031102姓名张泽宇康启萌余建军时间20xx年11月13日学校西北工业大学20xx3019xx20xx3019xx20xx3019xx一实验题目设计一个简...

UART串口通信实验报告

现代电路与系统实验报告实验四UART串口通信学院研究生院学号1400030034姓名张秋明一实验目的及要求设计一个UART串口通信协议实现串ltgt并转换功能的电路也就是通用异步收发器二实验原理UART是一种通...

R232串口通信实验报告1

R232串口通信实验基于VB语言实验报告RS232串口通信实验一实验题目1设计一个简单的基于串口通信的信息发送和接受界面或者是一个简单的聊天软件小的EXE可执行程序可以是两台PC机之间的通信也可以是一台PC上的...

用vc的串口通信实验报告

高级Internet编程高级Internet编程实验报告实验题目串口通信班级学号姓名日期20xx68高级Internet编程一实验要求把两台计算机的串口通过串口线连在一起通过串口实现两台计算机通讯可以利用高级语...

串口通信实验报告(34篇)