MCU与FPGA串口通信
FPGA以9600的波特率向单片机发送32位数据,然后单片机对数据进行解析,显示在显示屏上面
波特率的产生 : 9600bps是指每秒钟发送9600个bit,即1bit的时间为1/9600,fpga板子自带50M晶振,那么一bit的时间时1/9600/1/50M
在没有检验位的情况下,每一帧数据是10位 第一位起始位 0 2-9位 数据(低位在前,高位在后),第十位 终止位 1
FPGA程序思路 : 首先由fpga计数,每隔一段时间产生一个bps_clk,也就是波特率的驱动时钟,发送状态机共分为7个状态
IDLE : 发送起始标志为 TX_1 : 发送32数据的高八位,其中低位在前,高位在后 ...... STOP : 终止标志位 STOP_1 : 是专门用来延时的,刚开始没有延时状态
的情况下,FPGA向单片机发送数据过快,非常占用单片机的中断资源,所以加了一个延时模块 stop ,作用是:每发完一次数据等待100ms然后再发第二次数据,这样的
单片机就有时间干别的事情了。
MCU程序思路 : 首先在中断函数里面将FPGA发送过来的数据存到一个数组里面来处理,detect-uart()函数是用来分析数组的,首先检测数组里面的起始标志 ‘t’,如果没有检测到
终止标志位‘x’的话,对中间数据进行移位处理,还原以前的32位宽的数据,由于在数据传送时有误码的情况,所以在display中加了三级缓存,来减少出错的可能性。
module uart_tx( //global clock input clk, input rst_n, //uart interface output reg uart_tx, //user interface input [31:0] pinlv, input pinlv_value ); parameter BPS_9600 = 5208; //parameter BPS_9600 = 10; //count for bps_clk reg [14:0] cnt_bps_clk; always @(posedge clk or negedge rst_n) begin if(!rst_n) cnt_bps_clk <= 1'b0; else if(pinlv_value == 0) cnt_bps_clk <= 1'b0; else if(cnt_bps_clk == BPS_9600 - 1) cnt_bps_clk <= 1'b0; else cnt_bps_clk <= cnt_bps_clk + 1; end reg [31:0] cnt_bps_stop; wire stop_done; always @(posedge clk or negedge rst_n) begin if(!rst_n) cnt_bps_stop <= 0; else if(state == STOP) cnt_bps_stop <= 0; else if(cnt_bps_stop > 50_000_00) cnt_bps_stop <= 0; else cnt_bps_stop <= cnt_bps_stop + 1; end assign stop_done = (cnt_bps_stop == 49_000_00)? 1 : 0; //clk for bps reg bps_clk; always @(posedge clk or negedge rst_n) begin if(!rst_n) bps_clk <= 1'b0; else if(cnt_bps_clk == 1) bps_clk <= 1'b1; else bps_clk <= 1'b0; end //cnt for bps reg [14:0] bps_cnt; always @(posedge clk or negedge rst_n) begin if(!rst_n) bps_cnt <= 1'b0; else if(bps_cnt == 10) bps_cnt <= 0; else if(bps_clk) bps_cnt <= bps_cnt + 1'b1; else bps_cnt <= bps_cnt; end //tx state localparam IDLE = 4'd0; localparam TX_1 = 4'd1; localparam TX_2 = 4'd2; localparam TX_3 = 4'd3; localparam TX_4 = 4'd4; localparam STOP = 4'd5; localparam STOP_1 = 4'd6; //cnt state reg [3:0] state; always @(posedge clk or negedge rst_n) begin if(!rst_n) state <= IDLE; else if(state == STOP_1 && stop_done) state <= IDLE; else if(bps_cnt == 10 && (state != STOP_1)) state <= state + 1; end // state always @(posedge clk ) begin if(bps_clk) begin case(state) IDLE : // 't' di -- gao begin case(bps_cnt) 4'd0 : uart_tx <= 0; //begin 4'd1 : uart_tx <= 0;//data 4'd2 : uart_tx <= 0; 4'd3 : uart_tx <= 1; 4'd4 : uart_tx <= 0; 4'd5 : uart_tx <= 1; 4'd6 : uart_tx <= 1; 4'd7 : uart_tx <= 1; 4'd8 : uart_tx <= 0; 4'd9 : uart_tx <= 1; //stop default : uart_tx <= 1; endcase end TX_1 : //tx_1byte begin case(bps_cnt) 4'd0 : uart_tx <= 0; //begin 4'd1 : uart_tx <= pinlv[24];//data 4'd2 : uart_tx <= pinlv[25]; 4'd3 : uart_tx <= pinlv[26]; 4'd4 : uart_tx <= pinlv[27]; 4'd5 : uart_tx <= pinlv[28]; 4'd6 : uart_tx <= pinlv[29]; 4'd7 : uart_tx <= pinlv[30]; 4'd8 : uart_tx <= pinlv[31]; 4'd9 : uart_tx <= 1; //stop default : uart_tx <= 1; endcase end TX_2 : //tx_1byte begin case(bps_cnt) 4'd0 : uart_tx <= 0; //begin 4'd1 : uart_tx <= pinlv[16];//data 4'd2 : uart_tx <= pinlv[17]; 4'd3 : uart_tx <= pinlv[18]; 4'd4 : uart_tx <= pinlv[19]; 4'd5 : uart_tx <= pinlv[20]; 4'd6 : uart_tx <= pinlv[21]; 4'd7 : uart_tx <= pinlv[22]; 4'd8 : uart_tx <= pinlv[23]; 4'd9 : uart_tx <= 1; //stop default : uart_tx <= 1; endcase end TX_3 : //tx_1byte begin case(bps_cnt) 4'd0 : uart_tx <= 0; //begin 4'd1 : uart_tx <= pinlv[8];//data 4'd2 : uart_tx <= pinlv[9]; 4'd3 : uart_tx <= pinlv[10]; 4'd4 : uart_tx <= pinlv[11]; 4'd5 : uart_tx <= pinlv[12]; 4'd6 : uart_tx <= pinlv[13]; 4'd7 : uart_tx <= pinlv[14]; 4'd8 : uart_tx <= pinlv[15]; 4'd9 : uart_tx <= 1; //stop default : uart_tx <= 1; endcase end TX_4 : //tx_1byte begin case(bps_cnt) 4'd0 : uart_tx <= 0; //begin 4'd1 : uart_tx <= pinlv[0];//data 4'd2 : uart_tx <= pinlv[1]; 4'd3 : uart_tx <= pinlv[2]; 4'd4 : uart_tx <= pinlv[3]; 4'd5 : uart_tx <= pinlv[4]; 4'd6 : uart_tx <= pinlv[5]; 4'd7 : uart_tx <= pinlv[6]; 4'd8 : uart_tx <= pinlv[7]; 4'd9 : uart_tx <= 1; //stop default : uart_tx <= 1; endcase end STOP : // 'x' di -- gao begin case(bps_cnt) 4'd0 : uart_tx <= 0; //begin 4'd1 : uart_tx <= 0;//data 4'd2 : uart_tx <= 0; 4'd3 : uart_tx <= 0; 4'd4 : uart_tx <= 1; 4'd5 : uart_tx <= 1; 4'd6 : uart_tx <= 1; 4'd7 : uart_tx <= 1; 4'd8 : uart_tx <= 0; 4'd9 : uart_tx <= 1; //stop default : uart_tx <= 1; endcase end STOP_1 : begin uart_tx <= 1; end default : uart_tx <= 1; endcase end else uart_tx <= uart_tx; end endmodule
/*************** 用户定义参数 *****************************/ #define MAIN_Fosc 11059200L //define main clock #define Baudrate1 9600 //define the baudrate, 如果使用BRT做波特率发生器,则波特率跟串口2一样 //12T mode: 600~115200 for 22.1184MHZ, 300~57600 for 11.0592MHZ #define Baudrate2 19200 //define the baudrate2, //12T mode: 600~115200 for 22.1184MHZ, 300~57600 for 11.0592MHZ #define BUF_LENTH 20 //定义串口接收缓冲长度 /**********************************************************/ #include <reg51.h> sfr AUXR1 = 0xA2; sfr AUXR = 0x8E; sfr S2CON = 0x9A; //12C5A60S2双串口系列 sfr S2BUF = 0x9B; //12C5A60S2双串口系列 sfr IE2 = 0xAF; //STC12C5A60S2系列 sfr BRT = 0x9C; unsigned char uart1_wr; //写指针 unsigned char uart1_rd; //读指针 unsigned char xdata RX1_Buffer[BUF_LENTH]; bit B_TI; unsigned char uart2_wr; //写指针 unsigned char uart2_rd; //读指针 unsigned char xdata RX2_Buffer[BUF_LENTH]; bit B_TI2; long temp1 = 0; long temp2 = 0; long temp_buf1 = 0; long temp_buf2 = 0; long temp_buf3 = 0; long temp_buf = 0; long ce = 9999; /****************** 编译器自动生成,用户请勿修改 ************************************/ #define T1_TimerReload (256 - MAIN_Fosc / 192 / Baudrate1) //Calculate the timer1 reload value at 12T mode #define BRT_Reload (256 - MAIN_Fosc / 12 / 16 / Baudrate2) //Calculate BRT reload value #define TimeOut1 (28800 / (unsigned long)Baudrate1 + 2) #define TimeOut2 (28800 / (unsigned long)Baudrate2 + 2) #define TI2 (S2CON & 0x02) != 0 #define RI2 (S2CON & 0x01) != 0 #define CLR_TI2() S2CON &= ~0x02 #define CLR_RI2() S2CON &= ~0x01 /**********************************************************/ /******************** 本地函数声明 ***************/ void uart1_init(void); void UART1_TxByte(unsigned char dat); void PrintString1(unsigned char code *puts); void delay(char x) { char i = 0; char t= 0; for(i = 0;i<110;i++) { for(t = 0;t < x;t++); } } void detect_uart() { char i = 0; char flag = 0; temp1 = 0; for(i = 0;i <= uart1_wr ; i++) { // UART1_TxByte(RX1_Buffer[i]); if(flag) { if(RX1_Buffer[i] != 'x' ) { temp1 = temp1 << 8 ; temp1 = temp1 + RX1_Buffer[i]; // UART1_TxByte(RX1_Buffer[i]); } else temp2 = temp1; } if(RX1_Buffer[i] == 't') { flag = 1; } } } //void ceshi() //{ // ce = 0; // ce = ce << 8 ; // ce = ce + 0xff; // ce = ce << 8 ; // ce = ce + 0x0c; // ce = ce << 8 ; // ce = ce + 0xcc; // ce = ce << 8 ; // ce = ce + 0xcc; //// ce = 9999; //} void display() { char flag = 0; temp_buf3 = temp_buf2; temp_buf2 = temp_buf1; temp_buf1 = temp2; if(temp_buf3 == temp2) { temp_buf = temp2; } else { temp_buf = temp_buf; } UART1_TxByte('S');UART1_TxByte(' ');UART1_TxByte(' ');UART1_TxByte(' ');UART1_TxByte(' '); if(temp_buf/100000000 == 0) //bai M { UART1_TxByte(' '); } else { UART1_TxByte(temp_buf/100000000 + 0x30); flag = 1; } if(temp_buf/10000000%10 == 0 ) //shi M { if(!flag) { UART1_TxByte(' '); } else { UART1_TxByte(0x30); } } else { UART1_TxByte(temp_buf/10000000%10 + 0x30); flag = 1; } if(temp_buf/1000000%10 == 0 ) //M { if(!flag) { UART1_TxByte(' '); } else { UART1_TxByte(0x30); } } else { UART1_TxByte(temp_buf/1000000%10 + 0x30); flag = 1; } if(temp_buf/100000%10 == 0 ) //bai K { if(!flag) { UART1_TxByte(' '); } else { UART1_TxByte(0x30); } } else { UART1_TxByte(temp_buf/100000%10 + 0x30); flag = 1; } if(temp_buf/10000%10 == 0 ) //shi k { if(!flag) { UART1_TxByte(' '); } else { UART1_TxByte(0x30); } } else { UART1_TxByte(temp_buf/10000%10 + 0x30); flag = 1; } if(temp_buf/1000%10 == 0 ) // K { if(!flag) { UART1_TxByte(' '); } else { UART1_TxByte(0x30); } } else { UART1_TxByte(temp_buf/1000%10 + 0x30); flag = 1; } if(temp_buf/100%10 == 0 ) //bai { if(!flag) { UART1_TxByte(' '); } else { UART1_TxByte(0x30); } } else { UART1_TxByte(temp_buf/100%10 + 0x30); flag = 1; } if(temp_buf/10%10 == 0 ) //shi { if(!flag) { UART1_TxByte(' '); } else { UART1_TxByte(0x30); } } else { UART1_TxByte(temp_buf/10%10 + 0x30); flag = 1; } if(temp_buf%10 == 0 ) //ge { if(!flag) { UART1_TxByte(' '); } else { UART1_TxByte(0x30); } } else { UART1_TxByte(temp_buf%10 + 0x30); flag = 1; } } void main(void) { char i = 0; uart1_rd = 0; uart1_wr = 0; uart2_rd = 0; uart2_wr = 0; // AUXR |= 0x01; //串口1使用独立波特率发生器, 波特率跟串口2一样 AUXR1 |= (1<<4); //将UART2从P1口切换到 RXD2--P1.2切换到P4.2 TXD2---P1.3切换到P4.3 uart1_init(); PrintString1("串口1测试程序"); while(1) { display(); detect_uart(); } } void UART1_TxByte(unsigned char dat) { B_TI = 0; SBUF = dat; while(!B_TI); B_TI = 0; delay(10); } void PrintString1(unsigned char code *puts) //发送一串字符串 { for (; *puts != 0; puts++) UART1_TxByte(*puts); //遇到停止符0结束 } void uart1_init(void) { PCON |= 0x80; //UART0 Double Rate Enable SCON = 0x50; //UART0 set as 10bit , UART0 RX enable TMOD &= ~(1<<6); //Timer1 Set as Timer, 12T TMOD = (TMOD & ~0x30) | 0x20; //Timer1 set as 8 bits auto relaod TH1 = T1_TimerReload; //Load the timer TR1 = 1; ES = 1; EA = 1; } /**********************************************/ void UART0_RCV (void) interrupt 4 { if(RI) { RI = 0; RX1_Buffer[uart1_wr] = SBUF; if(++uart1_wr >= BUF_LENTH) uart1_wr = 0; } if(TI) { TI = 0; B_TI = 1; } }