Chinaunix首页 | 论坛 | 博客
  • 博客访问: 133538
  • 博文数量: 55
  • 博客积分: 1870
  • 博客等级: 上尉
  • 技术积分: 540
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-21 20:51
文章分类

全部博文(55)

文章存档

2011年(27)

2009年(3)

2008年(25)

我的朋友

分类: C/C++

2011-05-04 13:20:23

声明:本文转载于http://www.cnblogs.com/kingst,版权归黑金动力社区(http://www.heijin.org)所有。 

2010032423274411

简介

这一节,我们来说说RS232,俗称串口。大家对这东西应该很了解,没什么可说的。相对前面我们讲的内容,这一节比较复杂,我会尽力把它讲清楚。在这一节中,我不仅要给大家讲解如何去实现RS232功能,更重要的是要提出一种编程思想,如何让程序编写的更严谨,更专业,更有利于以后的维护和移植。

硬件开发

首先,我们要在NIOS II 软核中构建RS232模块。打开Quartus软件,双击进入SOPC BUILDER,然后点击下图所示红圈处,

clip_image002

点击后,如下图所示,红圈1处为波特率,我们设置为115200;红圈2处是是否允许通过软件改变波特率,我们选中,便是允许,这样我们就可以通过软件来随时更改波特率,如果软件不设置,默认值就是上面设置的115200;红框3中是设置一些与串口有关的参数,校验方式,数据位,停止位,后面那个基本不用,大家根据实际情况来修改。设置好以后,点击Next,Finish,完成构建。

clip_image004

构建好以后,将其更名为RS232,然后进行自动分配地址,自动分配中断号。一切就绪,点击General,进行编译。

编译好以后,退出,进入Quartus界面,给其分配引脚,如下图所示

clip_image006

然后运行TCL脚本,编译,等待……

编译好以后,大家可以选择自己的方式将程序下载到FPGA中,AS或JTAG都可以。

软件开发

打开NIOS II 9.0 IDE后,按快捷键Ctrl+b编译程序,等待编译……

编译好以后,我们再来看system.h文件。可以看到rs232部分的代码了,如下表所示,红圈处就是我们要用到的部分,大家已经熟悉了,一个是基地址,一个是中断号

01/*
02 
03* RS232 configuration
04 
05*
06 
07*/
08 
09#define RS232_NAME "/dev/RS232"
10 
11#define RS232_TYPE "altera_avalon_uart"
12 
13#define RS232_BASE 0x00201000
14 
15#define RS232_SPAN 32
16 
17#define RS232_IRQ 2
18 
19#define RS232_BAUD 115200
20 
21#define RS232_DATA_BITS 8
22 
23#define RS232_FIXED_BAUD 0
24 
25#define RS232_PARITY 'N'
26 
27#define RS232_STOP_BITS 1
28 
29#define RS232_SYNC_REG_DEPTH 2
30 
31#define RS232_USE_CTS_RTS 0
32 
33#define RS232_USE_EOP_REGISTER 0
34 
35#define RS232_SIM_TRUE_BAUD 0
36 
37#define RS232_SIM_CHAR_STREAM ""
38 
39#define RS232_FREQ 100000000
40 
41#define ALT_MODULE_CLASS_RS232 altera_avalon_uart

下面,我们开始编写软件程序,首先是修改sopc.h。如下表格所示

01typedef struct
02{
03    //接收寄存器
04    union{
05        struct{
06            volatile unsigned long int RECEIVE_DATA         :8;
07            volatile unsigned long int NC                   :24;          
08        }BITS;
09        volatile unsigned long int WORD;
10    }RXDATA;
11    //发送寄存器
12    union{
13        struct{
14            volatile unsigned long int TRANSMIT_DATA        :8;
15            volatile unsigned long int NC                   :24;           
16        }BITS;
17        volatile unsigned long int WORD;
18    }TXDATA;
19    //状态寄存器
20    union{
21        struct{
22            volatile unsigned long int PE                   :1;
23            volatile unsigned long int FE                   :1;
24            volatile unsigned long int BRK                  :1;
25            volatile unsigned long int ROE                  :1;
26            volatile unsigned long int TOE                  :1;
27            volatile unsigned long int TMT                  :1;
28            volatile unsigned long int TRDY                 :1;
29            volatile unsigned long int RRDY                 :1;
30            volatile unsigned long int E                    :1;
31            volatile unsigned long int NC                   :1;
32            volatile unsigned long int DCTS                 :1;
33            volatile unsigned long int CTS                  :1;
34            volatile unsigned long int EOP                  :1;
35            volatile unsigned long int NC1                  :19;           
36        } BITS;
37        volatile unsigned long int WORD;
38    }STATUS;
39    //控制寄存器
40    union{
41        struct{
42            volatile unsigned long int IPE                  :1;
43            volatile unsigned long int IFE                  :1;
44            volatile unsigned long int IBRK                 :1;
45            volatile unsigned long int IROE                 :1;
46            volatile unsigned long int ITOE                 :1;
47            volatile unsigned long int ITMT                 :1;
48            volatile unsigned long int ITRDY                :1;
49            volatile unsigned long int IRRDY                :1;
50            volatile unsigned long int IE                   :1;
51            volatile unsigned long int TRBK                 :1;
52            volatile unsigned long int IDCTS                :1;
53            volatile unsigned long int RTS                  :1;
54            volatile unsigned long int IEOP                 :1;
55            volatile unsigned long int NC                   :19;           
56        }BITS;
57        volatile unsigned long int WORD;
58    }CONTROL;
59    //波特率分频器
60    union{
61        struct{
62            volatile unsigned long int BAUD_RATE_DIVISOR    :16;
63            volatile unsigned long int NC                   :16;          
64        }BITS;
65        volatile unsigned  int WORD;
66    }DIVISOR;
67 
68}UART_STR;

这个结构体中包括5个共用体,这5个共用体对应RS232的5个寄存器,我们来看看这5个寄存器,下图所示,这个图来自《n2cpu_Embedded Peripherals.pdf》的第6-11页

clip_image008

这个图中的(1)有一个说明,就是说第7,8位根据设置的数据位有所改变,我们设置数据位8位,所以7,8位与前6为性质相同。

与之前讲的PIO的结构体类似,这个结构体的内容是按上图的寄存器顺序来定义的,(因为endofpacket没用到,所以在结构中没有定义)这样在操作过程中就可以实现相应的偏移量(offset)。

在这个结构体中,我们嵌套了5个共有体,在共用体中,我们又使用了结构体和位域。头一次看的一定很头晕。其实,我们这样做的目的就是想对寄存器的每一位进行单独的控制,同时也可以实现这个寄存器的整体控制。具体应用,我们在下面的程序中会应用到。

有了上面来的结构体以后,我们需要定义一个宏,跟PIO的类似。

1#define _UART
2 
3 
4#ifdef _UART
5 
6#define UART ((UART_STR *) RS232_BASE)
7 
8#endif

不用解释了吧,在PIO部分已经解释过了,应该没什么问题了吧。

接下来,我们要在inc下建立uart.h文件,如下图所示

clip_image010

建好以后,对uart.h进行编写,如下表所示

01/*
02 
03* =================================================================
04 
05* Filename: uart.h
06 
07* Description: The head of uart device driver
08 
09* Version:
10 
11* Created:
12 
13* Revision: none
14 
15* Compiler: Nios II IDE
16 
17*
18 
19* Author: AVIC
20 
21* Company: 金沙滩工作室
22 
23* ================================================================
24 
25*/
26 
27#ifndef UART_H_
28 
29#define UART_H_
30 
31#include "../inc/sopc.h"
32 
33#define BUFFER_SIZE 200
34 
35/*----------------------------------------------------------------
36 
37* Define
38 
39*---------------------------------------------------------------*/
40 
41typedef struct{
42 
43unsigned char mode_flag; //xmodem 1;uart 0;
44 
45unsigned int receive_flag;
46 
47unsigned int receive_count;
48 
49unsigned char receive_buffer[BUFFER_SIZE];
50 
51int (* send_byte)(unsigned char data);
52 
53void (* send_string)(unsigned int len, unsigned char *str);
54 
55int (* init)(void);
56 
57unsigned int (* baudrate)(unsigned int baudrate);
58 
59}UART_T;
60 
61extern UART_T uart;
62 
63#endif /*UART_H_*/

在上面的代码中,结构体UART_T很重要,它是模拟面向对象的一种编程思想,也是我之前说的一种很重要的编程方式。我们将与UART有关系的所有函数、变量都打包在一起,对其他函数来说,它们只能看到uart这个结构体,而里面的单独部分都是不可见的。希望大家可以好好体会其中的思想,对大家的编程一定会有很大的好处。

下面,我们要开始写RS232的驱动了,首先我们要在driver下面建立一个.c文件,命名为uart.c,如下图所示

clip_image012

建好以后,我们来编写uart.c文件,如下表所示

001/*
002 * =================================================================
003*       Filename:  uart.c
004 *
005 *    Description:  RS232 device driver
006 *
007 *        Version: 
008 *        Created: 
009 *       Revision:  none
010 *       Compiler:  Nios II IDE
011 *
012 *         Author:  AVIC
013 *        Company:  金沙滩工作室
014 * ===============================================================
015 */
016 
017/*--------------------------------------------------------------
018 *  Include
019 *-------------------------------------------------------------*/
020#include "sys/alt_irq.h"    
021#include "../inc/sopc.h"
022#include
023#include
024#include "../inc/uart.h"
025 
026/*--------------------------------------------------------------
027 *  Function Prototype
028*--------------------------------------------------------------*/
029static int uart_send_byte(unsigned char data);
030static void uart_send_string(unsigned int len, unsigned char *str);
031static int uart_init(void);
032static void uart_ISR(void);
033static int set_baudrate(unsigned int baudrate);
034 
035//初始化uart结构体,大家注意结构体的初始化方式
036UART_T uart={
037    .mode_flag=0,  
038    .receive_flag=0,
039    .receive_count=0,
040    .send_byte=uart_send_byte,
041    .send_string=uart_send_string,
042    .init=uart_init,
043    .baudrate=set_baudrate
044};
045 
046/*
047 * ===  FUNCTION  ==================================================
048 *         Name:  uart_send_byte
049 *  Description:  发送一个字节数据
050 * ================================================================
051 */
052static int uart_send_byte(unsigned char data)
053{
054    //将接收到的数据放到接收数据寄存器内,等待状态寄存器trdy置1,当trdy置1,说明接收完毕
055    UART->TXDATA.BITS.TRANSMIT_DATA = data;
056    while(!UART->STATUS.BITS.TRDY);
057 
058    return 0;
059}
060/*
061 * ===  FUNCTION  =================================================
062 *         Name:  uart_send_string
063 *  Description:  发送字符串数据
064 * ===============================================================
065 */
066static void uart_send_string(unsigned int len, unsigned char *str)
067{
068    while(len--)
069    {
070        uart_send_byte(*str++); 
071    }
072}
073/*
074 * ===  FUNCTION  =================================================================
075 *         Name:  uart_init
076 *  Description:  初始化程序
077 * ==============================================================
078 */
079static int uart_init(void)
080{
081     //设置波特率为115200
082    set_baudrate(115200);
083     
084     // 对控制寄存器的irrdy进行置1,表示当接收准备好后,中断使能  
085     UART->CONTROL.BITS.IRRDY=1;
086 
087    //清楚状态寄存器,这就是处理整个寄存器的方式,大家要注意
088     UART->STATUS.WORD=0;
089     
090    //注册uart中断,ISR为uart_ISR
091    alt_irq_register(RS232_IRQ, NULL, uart_ISR);
092 
093    return 0;
094}
095 
096/*
097 * ===  FUNCTION  ================================================
098 *         Name:  uart_ISR
099 *  Description:  串口中断
100 * ==============================================================
101 */
102static void uart_ISR(void)
103{
104    //等待状态寄存器的接收数据状态位rrdy,当rrdy位为1时,说明新接收的值传输到了接收数据寄存器
105    while(!(UART->STATUS.BITS.RRDY));
106     
107    //reveive_buffer为我们通过栈的方式在内存中开设的内存块,将接受数据寄存器中的数据到这个内存块中
108    uart.receive_buffer[uart.receive_count++] = UART->RXDATA.BITS.RECEIVE_DATA;
109     
110    //当接收数据的最后一位为\n(回车符)时,进入if语句,也就是说,\n作为了结束标志符,每次发送数据后,要加一个回车符作为结束符
111    if(uart.receive_buffer[uart.receive_count-1]=='\n'){
112         uart.receive_buffer[uart.receive_count]='\0';
113         uart_send_string(uart.receive_count,uart.receive_buffer);
114         uart.receive_count=0;
115         uart.receive_flag=1;
116    }
117}
118/*
119 * ===  FUNCTION  ===============================================
120 *         Name:  set_baudrate
121 *  Description:  设置波特率
122 * ==============================================================
123 */
124static int set_baudrate(unsigned int baudrate)
125{   
126    //设置波特率有一个公式的,波特率=时钟频率/(divisor+1),转换以后就是下面了。
127    UART->DIVISOR.WORD=(unsigned int)(ALT_CPU_FREQ/baudrate+0.5);
128 
129    return 0;
130}

编写好上面的函数以后,我们要修改main.c,如下表所示

01#include "../inc/sopc.h"
02#include "system.h"
03#include "sys/alt_irq.h"
04#include
05#include
06#include "../inc/uart.h"
07 
08int main()
09{
10    unsigned char buffer[50]="Hello FPGA!\n";
11     
12    //初始化串口,注意它的使用方法
1uart.init();
2 
3//循环发送字符串
1    while(1){
2        uart.send_string(sizeof(buffer),buffer);
3        usleep(500000);
4    }
5     
6    return 0;
7}

今天就讲到这,上面的讲解方式不知道大家觉得是否合适,如果有什么问题,请给我留言。

阅读(3007) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~