zoukankan      html  css  js  c++  java
  • 实验八--uart

    一。环境

      系统:ubuntu12.04

      开发板:jz2440

      编译器:gcc

    二。说明

        有空补上

    三。代码

          head.S

     1 @******************************************************************************
     2 @ File:head.S
     3 @ 功能:设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
     4 @******************************************************************************       
     5    
     6 .extern     main
     7 .text 
     8 .global _start 
     9 _start:
    10 Reset:                  
    11     ldr sp, =4096           @ 设置栈指针,以下都是C函数,调用前需要设好栈
    12     bl  disable_watch_dog   @ 关闭WATCHDOG,否则CPU会不断重启
    13     bl  clock_init          @ 设置MPLL,改变FCLK、HCLK、PCLK
    14 
    15     ldr pc, =on_sdram                   @ 跳到SDRAM中继续执行
    16 on_sdram:
    17     ldr sp, =0x34000000     @ 设置栈指针
    18     ldr lr, =halt_loop      @ 设置返回地址
    19     ldr pc, =main           @ 调用main函数
    20 halt_loop:
    21     b   halt_loop

    Makefile

     1 objs := head.o init.o serial.o main.o
     2 
     3 uart.bin: $(objs)
     4     arm-linux-ld -Ttext 0x00000000 -o uart_elf $^
     5     arm-linux-objcopy -O binary -S uart_elf $@
     6     arm-linux-objdump -D -m arm uart_elf > uart.dis
     7     
     8 %.o:%.c
     9     arm-linux-gcc -Wall -O2 -c -o $@ $<
    10 
    11 %.o:%.S
    12     arm-linux-gcc -Wall -O2 -c -o $@ $<
    13 
    14 clean:
    15     rm -f uart.bin uart_elf uart.dis *.o        
    16     

    init.c

     1 /*
     2  * init.c: 进行一些初始化
     3  */ 
     4 
     5 #include "s3c24xx.h"
     6  
     7 void disable_watch_dog(void);
     8 void clock_init(void);
     9 
    10 
    11 /*
    12  * 关闭WATCHDOG,否则CPU会不断重启
    13  */
    14 void disable_watch_dog(void)
    15 {
    16     WTCON = 0;  // 关闭WATCHDOG很简单,往这个寄存器写0即可
    17 }
    18 
    19 #define S3C2410_MPLL_200MHZ     ((0x5c<<12)|(0x04<<4)|(0x00))
    20 #define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))
    21 /*
    22  * 对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV
    23  * 有如下计算公式:
    24  *  S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s)
    25  *  S3C2410: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)
    26  *  其中: m = MDIV + 8, p = PDIV + 2, s = SDIV
    27  * 对于本开发板,Fin = 12MHz
    28  * 设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:2:4,
    29  * FCLK=200MHz,HCLK=100MHz,PCLK=50MHz
    30  */
    31 void clock_init(void)
    32 {
    33     // LOCKTIME = 0x00ffffff;   // 使用默认值即可
    34     CLKDIVN  = 0x03;            // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
    35 
    36     /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
    37 __asm__(
    38     "mrc    p15, 0, r1, c1, c0, 0
    "        /* 读出控制寄存器 */ 
    39     "orr    r1, r1, #0xc0000000
    "          /* 设置为“asynchronous bus mode” */
    40     "mcr    p15, 0, r1, c1, c0, 0
    "        /* 写入控制寄存器 */
    41     );
    42 
    43     /* 判断是S3C2410还是S3C2440 */
    44     if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
    45     {
    46         MPLLCON = S3C2410_MPLL_200MHZ;  /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
    47     }
    48     else
    49     {
    50         MPLLCON = S3C2440_MPLL_200MHZ;  /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
    51     }       
    52 }

    serial.c

     1 #include "s3c24xx.h"
     2 #include "serial.h"
     3 
     4 #define TXD0READY   (1<<2)
     5 #define RXD0READY   (1)
     6 
     7 #define PCLK            50000000    // init.c中的clock_init函数设置PCLK为50MHz
     8 #define UART_CLK        PCLK        //  UART0的时钟源设为PCLK
     9 #define UART_BAUD_RATE  115200      // 波特率
    10 #define UART_BRD        ((UART_CLK  / (UART_BAUD_RATE * 16)) - 1)
    11 
    12 /*
    13  * 初始化UART0
    14  * 115200,8N1,无流控
    15  */
    16 void uart0_init(void)
    17 {
    18     GPHCON  |= 0xa0;    // GPH2,GPH3用作TXD0,RXD0
    19     GPHUP   = 0x0c;     // GPH2,GPH3内部上拉
    20 
    21     ULCON0  = 0x03;     // 8N1(8个数据位,无较验,1个停止位)
    22     UCON0   = 0x05;     // 查询方式,UART时钟源为PCLK
    23     UFCON0  = 0x00;     // 不使用FIFO
    24     UMCON0  = 0x00;     // 不使用流控
    25     UBRDIV0 = UART_BRD; // 波特率为115200
    26 }
    27 
    28 /*
    29  * 发送一个字符
    30  */
    31 void putc(unsigned char c)
    32 {
    33     /* 等待,直到发送缓冲区中的数据已经全部发送出去 */
    34     while (!(UTRSTAT0 & TXD0READY));
    35     
    36     /* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */
    37     UTXH0 = c;
    38 }
    39 
    40 /*
    41  * 接收字符
    42  */
    43 unsigned char getc(void)
    44 {
    45     /* 等待,直到接收缓冲区中的有数据 */
    46     while (!(UTRSTAT0 & RXD0READY));
    47     
    48     /* 直接读取URXH0寄存器,即可获得接收到的数据 */
    49     return URXH0;
    50 }
    51 
    52 /*
    53  * 判断一个字符是否数字
    54  */
    55 int isDigit(unsigned char c)
    56 {
    57     if (c >= '0' && c <= '9')
    58         return 1;
    59     else
    60         return 0;       
    61 }
    62 
    63 /*
    64  * 判断一个字符是否英文字母
    65  */
    66 int isLetter(unsigned char c)
    67 {
    68     if (c >= 'a' && c <= 'z')
    69         return 1;
    70     else if (c >= 'A' && c <= 'Z')
    71         return 1;       
    72     else
    73         return 0;
    74 }

    main.c

     1 #include "serial.h"
     2 
     3 int main()
     4 {
     5     unsigned char c;
     6     uart0_init();   // 波特率115200,8N1(8个数据位,无校验位,1个停止位)
     7 
     8     while(1)
     9     {
    10         // 从串口接收数据后,判断其是否数字或子母,若是则加1后输出
    11         c = getc();
    12         if (isDigit(c) || isLetter(c))
    13             putc(c+1);
    14     }
    15 
    16     return 0;
    17 }

    注:代码源自韦东山先生,简作修改。

    删掉sdram部分内容

    上面代码只是测试串口用,下面贴出实用的串口代码,可以输出打印信息,这点在uboot和内核很有用

    而且这里不用硬件重定向

    对于上面代码作修改如下

    serial.c里面添加:

     1 void puts(unsigned char *str)
     2 {
     3     int i=0;
     4     while(str[i])
     5     {
     6       putc(str[i]);
     7       i++;    
     8     }    
     9 
    10 
    11 }

    当然serial.h里面也相应的删减,去掉对输入字符判断函数

    此外,mian函数可以作出一个菜单选项

     1 #include "serial.h"
     2 
     3 int main()
     4 {
     5     unsigned char c;
     6     uart0_init();   // 波特率115200,8N1(8个数据位,无校验位,1个停止位)
     7 
     8     while(1)
     9     {
    10         // 从串口接收数据后,判断其是否数字或子母,若是则加1后输出
    11         c = getc();
    12     switch(c)
    13     {
    14       case '0':
    15         {
    16         puts("I
    
    ");
    17         break;
    18         }    
    19       case '1':
    20         {
    21         puts("AM
    
    ");
    22         break;    
    23         }
    24       case '2':
    25         {
    26         puts("HELLO
    
    ");
    27         break;
    28         }    
    29       case '3':        
    30         {
    31         puts("WORLD
    
    ");
    32         break;    
    33         }
    34       default:
    35         {
    36         puts("thanks!
    
    ");
    37         break;    
    38         }
    39     }
    40     }
    41 
    42     return 0;
    43 }

    输出会相对输入作出不同响应,在后面做菜单方面很有用。

    韦东山老师用作菜单的串口函数是硬件重定向,没这个简练

    经测试,可用。

  • 相关阅读:
    HDOJ 1069_大二写
    HDOJ 2037:今年暑假不AC_大二写
    第二次HDOJ:1058
    HDOJ 1019
    第二次 HDOJ 1003
    第二次做HDOJ 1051
    memset()的用法
    数据结构中的频度含义
    程序框图的书写
    python课堂整理22----装饰器进阶
  • 原文地址:https://www.cnblogs.com/hulig7/p/4115273.html
Copyright © 2011-2022 走看看