zoukankan      html  css  js  c++  java
  • 【嵌入式】——arm裸机开发 step by step 之 串口通信

    一、在使用S5PV210的串口发送和接收的时候,首先要对S5PV210的串口进行配置,我们使用轮询方式时的配置有哪些?

    1、配置GPIO,使对应管脚作为串口的发送和接收管脚

      GPA0 0 1 管脚 2 3 可以配置,但我们没有使用
      GPA0CON寄存器[7:4][3:0] 0x22
      GPA0PUD寄存器[3:0] 0 禁止上下拉电阻
    2、配置串口单元本身寄存器
      ULCON0 0xE2900000
      数据位:8位
      停止位:1位
      校验位:无
      使用的正模式,非红外。
    3、UCON0 0xE2900004

      串口的收发模式:轮训

      串口的时钟使用的PCLK  UFCON0 0xE2900008

      禁止FIFO
      UMCON0 0xE290000C
      禁止Modem
      UBRDIV0 0xE2900028
      UDIVSLOT0 0xE290002C
      UBRDIV0 = PCLK或者SCLK_UART/波特率/16 - 1 的整数部分
      UDIVSLOT0 查表,怎么查?
      PCLK或者SCLK_UART/波特率/16 - 1 的小数部分 * 16 取整
      查表
      PCLK=66500000
      波特率是115200
      UBRDIV0 = 35
      UDIVSLOT0 = 0x0080
      发送数据流程(轮询方式)
      uart0_putc()
      判断UTRSTAT0的BIT1,如果BIT1是0等待如果BIT1是1,就把要发送的一个字节数据写到发送寄存器(UTXH0,0xE2900020)
    接收数据流程(轮询方式)
      uart0_getc
      判断UTRSTAT0的BIT0,如果BIT0是0等待如果BIT0是1,从URXH0 0xE2900024读取一个字节的数据。

    编程时:
    0xE2900000地址单元写3
    0xE2900004地址单元写5
    0xE2900008地址单元写0
    0xE290000C地址单元写0
    0xE2900028地址单元写35
    0xE290002C地址单元写0x80

    uart.h

     1 #ifndef _UART_H_
     2 #define _UART_H_
     3 
     4 #define GPA0CON (*(volatile unsigned int *)0xE0200000)
     5 #define GPA0PUD (*(volatile unsigned int *)0xE0200008)
     6 
     7 #define ULCON0 (*(volatile unsigned int *)0xE2900000)
     8 #define UCON0 (*(volatile unsigned int *)0xE2900004)
     9 #define UFCON0 (*(volatile unsigned int *)0xE2900008)
    10 #define UMCON0 (*(volatile unsigned int *)0xE290000C)
    11 #define UTRSTAT0 (*(volatile unsigned int *)0xE2900010)
    12 #define UTXH0 (*(volatile unsigned int *)0xE2900020)
    13 #define URXH0 (*(volatile unsigned int *)0xE2900024)
    14 #define UBRDIV0 (*(volatile unsigned int *)0xE2900028)
    15 #define UDIVSLOT0 (*(volatile unsigned int *)0xE290002C)
    16 
    17 #define PCLK (66500000)
    18 
    19 //函数原型声明
    20 extern void uart0_init(void);
    21 extern void uart0_puts(const char *);
    22 extern void uart0_putc(char);
    23 extern char uart0_getc(void);
    24 extern void uart0_gets(char *,int);
    25 
    26 #endif // _UART_H_

    uart.c

     1 #include "uart.h"
     2 
     3 //初始化串口寄存器
     4 void uart0_init(void){
     5     //配置GPIO口 根据CPU 手册中设置下面的寄存器
     6     //GPA0CON GPA0PUD
     7     ULCON0 = 3;
     8     UCON0 = 5;
     9     UFCON0 = 0;
    10     UMCON0 = 0;
    11     UBRDIV0 = 35;
    12     UDIVSLOT0 = 0x0080;
    13     GPA0CON = 34;
    14     GPA0PUD = ~0xF;
    15 }
    16 //发送一个字符
    17 void uart0_putc(char c){
    18     //判断状态位
    19     while(!(UTRSTAT0 & (1<<1)));
    20     //发送字符
    21     UTXH0 = c;
    22 }
    23 //接收一个字符
    24 char uart0_getc(void){
    25     while(!(UTRSTAT0 & 1));
    26 
    27     return URXH0;
    28 }
    29 
    30 //接收一串字符
    31 void uart0_gets(char *str,int len){
    32     char* tmp = str;
    33     int in = len;
    34     //int i;
    35     while(--len){
    36         *tmp = uart0_getc();
    37         if(*tmp == '
    '){
    38             uart0_putc('
    '); //若此处为 
     则不会输出,若为 
     则在下一行跳跃输出字符的长度,然后输出字符串
    39             uart0_putc('
    ');
    40             break;
    41         }
    42         if(*tmp == 127){  //127 是 ubuntu下 kermit软件中的 BACKSPACE按键 需要实现的效果就是当按下回车键的时候终端的上一个数据会被删掉, 
    43             len++;  //由于此分支的 127 输入到了 *tmp 中,此时的127是无用的,所以要进行 len++ ,但是有一个问题,我们的退格的目的是删除上一个字母,所以127的上一个字符也没用了,需要对len做两次自加进行还原  但是又出现一个问题,如果已经删到第0个元素就不能再自加两次了,这样会造成 len 越来越大。因此要在下面做一个判断
    44             if(len < in){ 
    45                 len++;
    46             }
    47             if(tmp == str){
    48                 continue;
    49             }
    50 
    51             uart0_putc('');
    52             uart0_putc(' ');
    53             uart0_putc('');
    54             --tmp;
    55             continue;
    56         }
    57         uart0_putc(*tmp);
    58         tmp++;
    59     }
    60     *tmp = 0; 
    61 }
    62 
    63 //发送一串字符
    64 void uart0_puts(const char *str){
    65     if(str == 0){
    66         return;
    67     }
    68     while(*str){
    69         uart0_putc(*str);
    70         if(*str == '
    '){
    71             uart0_putc('
    ');
    72         }
    73         str++;
    74     }
    75 }

    main.c

     1 #include "uart.h"
     2 
     3 void main(void){
     4     char val[30]; 
     5     uart0_init();
     6     while(1){
     7         
     8         //uart0_gets(val);
     9         uart0_puts("
    start
    ");
    10         uart0_gets(val,30);
    11         uart0_puts(val);
    12         
    13       //  uart0_puts(uart0_getc());
    14     }
    15 }

    makefile

     1 PROG=uart
     2 OBJS=main.o uart.o
     3 
     4 AS=arm-linux-as
     5 CC=arm-linux-gcc
     6 LD=arm-linux-ld
     7 OBJCOPY=arm-linux-objcopy
     8 AFLAGS=-march=armv5te
     9 CFLAGS=-march=armv5te -nostdlib
    10 LDFLAGS=-nostartfiles -nostdlib -Ttext=0x20008000 -e main
    11 
    12 $(PROG): $(OBJS)
    13     $(LD) $(LDFLAGS) -o $(PROG)  $(OBJS)
    14     $(OBJCOPY) -O binary $(PROG) $(PROG).bin
    15     cp uart.bin /tftpboot
    16 
    17 %.o:%.s
    18     $(AS) $(AFLAGS) -o $@  $<
    19 
    20 %.o:%.c
    21     $(CC) $(CFLAGS) -c -o $@  $<
    22 clean:
    23     @rm -vf $(OBJS) $(PROG) $(PROG).bin

     二、arm9 TQ2440

      这款 arm9 的串口通信跟 上面的 S5PV210相似:

    uart.h

     1 #ifndef __UART_H__
     2 #define __UART_H__
     3 
     4 //gpio
     5 #define GPHCON (*(volatile unsigned long*)0x56000070) 
     6 #define GPHUP (*(volatile unsigned long*)0x56000078)
     7 
     8 //uart0 register
     9 #define ULCON0   (*(volatile unsigned long*)0x50000000) //设置传输格式
    10 #define UCON0    (*(volatile unsigned long*)0x50000004) //选择时钟源和中断方式
    11 #define UFCON0   (*(volatile unsigned long*)0x50000008) //是否使用FIFO
    12 #define UMCON0   (*(volatile unsigned long*)0x5000000C) //流量控制模式
    13 #define UTRSTAT0 (*(volatile unsigned long*)0x50000010) //设置状态寄存器 [0] 当接收到数据时,此位被自动设为1 [1] 当发送缓冲区中没有数据时,此位被设置为1 [2] 当发送缓冲区中没有数据,并且最后一个数据也已经发送出去时,此位被自动设为1
    14 #define UBRDIV0  (*(volatile unsigned long*)0x50000028) //设置波特率
    15 
    16 //收发数据寄存器
    17 #define UTXH0    (*(volatile unsigned long*)0x50000020) //发数据
    18 #define URXH0    (*(volatile unsigned long*)0x50000024) //收数据
    19 #define UTXH0B    (*(volatile unsigned long*)0x50000023) //发数据
    20 #define URXH0B    (*(volatile unsigned long*)0x50000027) //收数据
    21 
    22 //函数声明
    23 extern void uart0_init(void);
    24 extern char uart0_getc(void);
    25 extern void uart0_putc(char);
    26 extern void uart0_gets(char *,int);
    27 extern void uart0_puts(char *);
    28 
    29 #endif

    uart.c

     1 #include "uart.h"
     2 
     3 void uart0_init(void){
     4     //配置 gpio 管脚
     5     GPHCON &= ~0xf0;
     6     GPHCON |= 0xa0;
     7     //GPHUP &= 0x0c;  //设置 gph2 gph3 内部上拉
     8     GPHUP &= ~0x6;    //设置 gph2 gph3 上下拉电阻禁止
     9 
    10     ULCON0 = 3;     //数据位 8位 一个停止位 无校检 正常模式
    11     UCON0 = 5;      //查询方式
    12     UFCON0 = 0;     //禁止FIFO
    13     UMCON0 = 0;     //禁止流量控制
    14     UBRDIV0 = 50000000/(115200*16)-1;   //26
    15 }
    16 
    17 char uart0_getc(void){
    18     char ch;
    19     while(!(UTRSTAT0 & 1));
    20     //ch = URXH0;
    21     return URXH0;
    22 }
    23 
    24 void uart0_putc(char ch){
    25     while(!(UTRSTAT0 & (1<<2)));
    26     UTXH0 = ch;
    27 }
    28 
    29 void uart0_gets(char* ch,int len){
    30     int flag = len;
    31     while(--len){
    32         *ch = uart0_getc();
    33         if(*ch == '
    '){
    34             uart0_putc(*ch);
    35             break;
    36         }
    37         if(*ch == 8){   //在dnw中 BACK SPACE按键是8 在 kermit下是127
    38             len++;  //此次循环接收的是退格符号所以无论如何len都要自加
    39             if(flag == len){    //为了防止回删到开头,所以做个限制
    40                 continue;
    41             }
    42             uart0_putc('');
    43             uart0_putc(' ');
    44             uart0_putc('');
    45             len++;
    46             ch--;
    47             continue;
    48         }
    49         uart0_putc(*ch);
    50         ch++;
    51     }
    52     *ch = 0;
    53 
    54 }
    55 void uart0_puts(char* ch){
    56     while(*ch){
    57         uart0_putc(*ch);
    58         //如果是在kermit 下需要用到下面代码;
    59         /*
    60         if(*ch == '
    '){
    61             uart0_putc('
    ');
    62         }
    63         */
    64         ch++;
    65     }
    66     
    67 }

    main.c

     1 #include "uart.h"
     2 
     3 void delay(void);
     4 
     5 int main(void){
     6     uart0_init();
     7 
     8     uart0_puts("ok start:
    ");
     9     while(1){
    10         char ch[30]; 
    11         uart0_puts("netboy# ");
    12         uart0_gets(ch,5);
    13         uart0_puts(ch);
    14         uart0_puts("
    ");
    15     }
    16     return 0;
    17 }
    18 
    19 void delay(void){
    20     int i;
    21     for(i = 0; i < 0xf0000; i++){
    22         ;
    23     }
    24 }

    uart.lds

     1 SECTIONS
     2 {
     3     . = 0x30000000;
     4     .text :{
     5        main.o (.text);
     6        *.o (.text);
     7     }
     8     .data :{
     9         *.o (.data);
    10     }
    11     __bss_start = .;
    12     .bss :{
    13         *.o (.bss);
    14     }
    15     __end = .;
    16 };

    Makefile

     1 PROG=uart
     2 OBJS=main.o uart.o
     3 
     4 CC=arm-linux-gcc
     5 LD=arm-linux-ld
     6 OBJCOPY=arm-linux-objcopy
     7 AFLAGS=-march=armv5te
     8 CFLAGS=-march=armv5te -nostdlib
     9 LDFLAGS=-nostartfiles -nostdlib -Ttext=0x30000000 -e main
    10 
    11 $(PROG): $(OBJS)
    12     $(LD) $(LDFLAGS) -o $(PROG) $(OBJS)
    13     $(OBJCOPY) -O binary $(PROG) $(PROG).bin
    14     cp uart.bin /mnt/hgfs/linux_share/tq2440/
    15 %.o:%.c
    16     $(CC) $(CFLAGS) -c -o $@ $<
    17 
    18 clean:
    19     @rm -vf $(PROG) $(OBJS) $(PROG).bin 
  • 相关阅读:
    pip或easy_install安装库报错:SSL: CERTIFICATE_VERIFY_FAILED
    js 闭包
    php 安装xdebug进行调试(phpstorm)
    Linux下一个最简单的不依赖第三库的的C程序(2)
    Linux下一个最简单的不依赖第三库的的C程序(1)
    windbg .net 程序的死锁检测 常用方法(个人备份笔记)
    自定义经纬度索引(非RTree、Morton Code[z order curve]、Geohash的方式)
    通过经纬度坐标计算距离的方法(经纬度距离计算)
    根据2个经纬度点,计算这2个经纬度点之间的距离(通过经度纬度得到距离)
    The version of SOS does not match the version of CLR you are debugging; SOS.dll版本不匹配; Dump文件不同环境mscordacwks.dll版本问题
  • 原文地址:https://www.cnblogs.com/ngnetboy/p/3612609.html
Copyright © 2011-2022 走看看