嵌入式Linux驱动学习之USART串口控制:基于AT91SAM9261EK

来源:互联网 发布:如何做软件代理商 编辑:程序博客网 时间:2024/06/07 21:46

    普通单片机的串口操作比较容易,但是基于Linux系统的串口操作难不难呢?其实,基于Linux操作系统的串口操作分为两个部分:串口驱动部分(底层驱动与设备注册)与串口的应用程序(用户程序)。一般厂家或是Linux内核已经提供了基于开发板的串口驱动,只需要修改或是注册相应的串口设备,就可以直接使用了。因此,只需要写用户应用程序即可。

   我手头上有一块AT91SAM9261EK的开发板,为了学习Linux买的,现在用到了,因此,学习一下串口的操作。


   首先看一下内核是否注册了所有的串口及开发板可用的串口,查看硬件板子,我这里有 三个串口,其中一个为:DEBUG串口,另外两个串口可以用来测试。启动开发板,Linux启动信息会在控制台打印出串口注册的相关信息,开始只有DEBUG注册了,因此,需要修改内核里的开发板相关的文件:我这里为:

linux-2.6.32.2/arch/arm/mach-at91/board-sam9261ek.c

找到相应的串口初始化注册的函数:

static void __init ek_map_io(void)
{
    /* Initialize processor: 18.432 MHz crystal */
    at91sam9261_initialize(18432000);

    /* Setup the LEDs */
    at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);

    /* DBGU on ttyS0. (Rx & Tx only) */
    at91_register_uart(0, 0, 0);

    /* Add USART0 USART1 USART2 */
    at91_register_uart(AT91SAM9261_ID_US0, 1, 0);
    at91_register_uart(AT91SAM9261_ID_US1, 2, 0);
    at91_register_uart(AT91SAM9261_ID_US2, 3, 0);

    /* set serial console to ttyS0 (ie, DBGU) */
    at91_set_serial_console(0);
}


    然后重新编译内核,发现另外三个串口的设备注册成功。分别为:

atmel_usart.0: ttyS0 at MMIO 0xfefff200 (irq = 1) is a ATMEL_SERIAL
atmel_usart.1: ttyS1 at MMIO 0xfffb0000 (irq = 6) is a ATMEL_SERIAL
atmel_usart.2: ttyS2 at MMIO 0xfffb4000 (irq = 7) is a ATMEL_SERIAL
atmel_usart.3: ttyS3 at MMIO 0xfffb8000 (irq = 8) is a ATMEL_SERIAL

        串口注册成功,操作的方式就像打开文件一样了。分别为 /dev/ttyS0 /dev/ttyS1 /dev/ttyS2

       下面为操作串口的应用程序,为网上找到,自己修改了一下,实验好用。连接好串口线,DEBUG也连接,我这里使用USB转串口的,设置好波特率:程序里设置为:9600 8 N 1,串口助手发送,开发板收到后,通过DEBUG口打印接收到的,并且再通过相应的串口发送回来。

这里涉及到串口的配置,文件的open 与write。

程序如下:


//rs232_test.c#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#include <termios.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <sys/time.h>#define BAUDRATE B9600static int open_com(char *dev_name, long com_baud, int com_data, int com_pry, int com_stop){uintbaud = 0, data = 0, parity = 0, stop = 0;structtermiosstrNewTio;intfd;//set baudrate:switch(com_baud) {case 50: baud = B50; break;case 75: baud = B75; break;case 110: baud = B110; break;case 134: baud = B134; break;case 150: baud = B150; break;case 200: baud = B200; break;case 300: baud = B300; break;case 600: baud = B600; break;case 1200: baud = B1200; break;case 1800: baud = B1800; break;case 4800: baud = B4800; break;case 9600: baud = B9600; break;case 19200: baud = B19200; break;case 38400: baud = B38400; break;case 57600: baud = B57600; break;case 115200: baud = B115200; break;case 230400: baud = B230400; break;default:baud = B9600;}//set databits:switch(com_data) {case 5:data = CS5; break;case 6:data = CS6; break;case 7:data = CS7; break;case 8:data = CS8; break;default:data = CS8;}//set parity:switch(com_pry) {case 0: parity = 0; break;case 1: parity = PARENB | PARODD; break;case 2: parity = PARENB; break;default:parity = 0;}//set stopbits:switch(com_stop) {case 1: stop = 0; break;case 2: stop = CSTOPB; break;default:stop = 0;}fd = open(dev_name, O_RDWR | O_NOCTTY );if (fd < 0) {perror("com  open() error");return -1;}//set parameters:tcgetattr(fd, &strNewTio);strNewTio.c_cflag = baud | data | parity | stop | CREAD | CLOCAL;strNewTio.c_iflag = 0;strNewTio.c_lflag = 0;strNewTio.c_oflag = 0;if (tcsetattr(fd, TCSANOW, &strNewTio) < 0) {close(fd);perror("com tcsetattr()  error");return -1;}return fd;}int main(int argc, char *argv[]){    struct timeval tp;    long time1=0;    long time2=0;    int fd1,fd2;    struct termios tio1,tio2;    int res,cnt,i;    int mode = 1;            //rs232 mode    unsigned char c;        unsigned char dev1[10];    unsigned char dev2[10];    int tmp1,tmp2;    if (argc == 0x0) {        printf("Usage : rs232 com_no\n");        return 0;    }    else {        tmp1 = atoi(argv[1]);                if (tmp1 > 16 ) {            printf("Usage : rs232_loopback com_no com_no\n");            return 0;        }        else {                    sprintf(dev1, "/dev/ttyS%d", tmp1);        }    }    fd1 = open_com(dev1, 9600, 8, 0, 1);           if (fd1 < 0) {        printf("can not open %s\n", dev1);        close(fd1);        return 0;    }    else{ printf("Open COM %s Success!!\n", dev1);    }   // clear the noise, made by change UART modeusleep(10000);charwr = 'k';charrd [1000];intret;rd[0] = 0;while(1){printf("=======%d\n ", i++);//write(fd1, &wr, 1);printf("=send:%c ", wr);usleep(100);ret = read(fd1, rd, 512);if (ret){printf("\n=========receive:%s\n", rd);write(fd1, rd, strlen(rd));memset(rd, 0, 512);}}return 0;}


      Makefile文件如下:

all:
arm-none-linux-gnueabi-gcc rs232_test.c -o rs232_test
clean:
rm -rf *.o rs232_test


    在Shell下直接 执行#   make,就可以生成在开发板上运行的交叉编译的可执行文件,设置一下执行权限,chmod 777 rs232_test

     然后连接好此串口的串口线,通过ftp等放到开发板的根文件系统里,在执行目录下执行:


#  ./rs232_test 1              //这里打开/dev/ttyS1

打开成功,就会提示成功的信息,就可以通过串口助手往相应的串口上发送数据了。


      通过串口助手发送数据,串口助手就可以收到回复,回复的内容是发送的内容。同时DEBUG控制台会打印出收到的信息。
     至此,基本的串口操作实现了。
0 0
原创粉丝点击