zoukankan      html  css  js  c++  java
  • TQ210裸机编程(6)——UART(1)

    S5PV210包含4个异步收发器(UART),提供4个独立的异步串行输入/输出(I/O)端口。所有端口可工作于中断模式或DMA模式。提供高达3Mbps的位速率。每个UART包含2个FIFO用于接收和发送数据。

    具有可编程的波特率、红外收发、1位或2位停止位、5~8位数据位、校验。


    UART框图如下:

    数据发送:要发送的数据帧是可编程的。它包含1位起始位,5~8位数据位,1个选项校验位,1或2位停止位,这些都通过ULCONn寄存器来设置。在FIFO模式下发送器将要发送的数据发送给Tx FIFO,在非FIFO模式下,发送器将要发送的数据发送给Tx保持寄存器

    数据接收:和数据发送类似。


    串口编程操作步骤:

    1、配置时钟,选择时钟源

    2、配置ULCONn寄存器:设置数据位、停止位校验位、模式

    3、配置UCONn寄存器:设置数据接收和发送模式、时钟源

    3、设置UFCONn:启用或静止FIFO

    4、配置UBRDIVn和UDIVSLOTn:计算波特率

    5、发送数据:等待发送器为空,将要发送的8位数据赋给发送缓存寄存器UTXHn

    6、接收数据:等待接收缓冲区有数据可读,从接收缓存寄存器URXHn中取出数据。


    波特率计算:

    DIV_VAL = UBRDIVn + (num of 1's in UDIVSLOTn)/16
    DIV_VAL = (PCLK / (bps x 16)) −1
    或者
    DIV_VAL = (SCLK_UART / (bps x 16)) −1

    比如配置波特率为115200bps,时钟源选择PCLK=66MHz

    DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
    UBRDIV0 = 34 (DIV_VAL的整数部分)
    (num of 1's in UDIVSLOTn)/16 = 0.8 (DIV_VAL的小数部分)
    (num of 1's in UDIVSLOTn) = 12
    UDIVSLOT0 = 0xDDDD (查表)



    实验效果:

    按数字1则改变LED1的状态;按数字2改变LED2的状态。


    代码:

    start.S

    .global _start				/* 声明一个全局的标号 */
    _start:
    	bl clock_init			/* 时钟初始化 */
    	bl uart_init			/* 串口初始化 */
    	bl main					/* 跳转到C函数去执行 */
    halt:
    	b halt
    

    clock.c

    #define APLLCON0		*((volatile unsigned int *)0xE0100100)
    #define MPLLCON			*((volatile unsigned int *)0xE0100108)
    #define EPLLCON0		*((volatile unsigned int *)0xE0100110)
    #define VPLLCON			*((volatile unsigned int *)0xE0100120)
    #define CLK_SRC0 		*((volatile unsigned int *)0xE0100200)
    #define CLK_DIV0		*((volatile unsigned int *)0xE0100300)
    #define CLK_DIV1		*((volatile unsigned int *)0xE0100304)
    #define CLK_DIV2		*((volatile unsigned int *)0xE0100308)
    #define CLK_DIV3		*((volatile unsigned int *)0xE010030C)
    
    void clock_init()
    {
    	/* 1、设置PLL_LOCK寄存器(这里使用默认值) */
    	/* 2、设置PLL_CON寄存器(使用芯片手册推荐的值) */
    	APLLCON0	= (1 << 0) | (3 << 8) | (125 << 16) | (1 << 31);	/* FOUTAPLL = 1000MHz */
    	MPLLCON 	= (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31);	/* FOUTMPLL = 667MHz */
    	EPLLCON0 	= (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31);	/* FOUTEPLL = 96MHz */
    	VPLLCON 	= (3 << 0) | (6 << 8) | (108 << 16) | (1 << 31);	/* FOUTVPLL = 54MHz */
    	
    	/* 3、选择PLL为时钟输出 */
    	/* MOUT_MSYS = SCLKAPLL = 1000MHz
    	** MOUT_DSYS = SCLKMPLL = 667MHz
    	** MOUT_PSYS = SCLKMPLL = 667MHz
    	*/
    	CLK_SRC0 = (1 << 0) | (1 << 4) | (1 << 8) | (1 << 12);
    	
    	/* 4、设置系统时钟分频值 */
    	/* freq(ARMCLK) = MOUT_MSYS / (APLL_RATIO + 1) = 1000MHz / (0 + 1) = 1000MHz
    	** freq(HCLK_MSYS) = ARMCLK / (HCLK_MSYS_RATIO + 1) = 1000MHz / (4 + 1) = 200MHz
    	** freq(PCLK_MSYS) = HCLK_MSYS / (PCLK_MSYS_RATIO + 1) = 200MHz / (1 + 1) = 100MHz
    	** freq(HCLK_DSYS) = MOUT_DSYS / (HCLK_DSYS_RATIO + 1) = 667 / (3 + 1) = 166MHz
    	** freq(PCLK_DSYS) = HCLK_DSYS / (PCLK_DSYS_RATIO + 1) = 166 / (1 + 1) = 83MHz
    	** freq(HCLK_PSYS) = MOUT_PSYS / (HCLK_PSYS_RATIO + 1) = 667 / (4 + 1) = 133MHz
    	** freq(PCLK_PSYS) = HCLK_PSYS / (PCLK_PSYS_RATIO + 1) = 133 / (1 + 1) = 66MHz
    	*/
    	CLK_DIV0 = (0 << 0) | (4 << 8) | (1 << 12) | (3 << 16) | (1 << 20) | (4 << 24) | (1 << 28);
    }


    uart.c

    #define GPA0CON		*((volatile unsigned int *)0xE0200000)
    #define ULCON0 		*((volatile unsigned int *)0xE2900000)
    #define UCON0 		*((volatile unsigned int *)0xE2900004)
    #define UFCON0 		*((volatile unsigned int *)0xE2900008)
    #define UTRSTAT0 	*((volatile unsigned int *)0xE2900010)
    #define UTXH0  		*((volatile unsigned int *)0xE2900020)
    #define URXH0 		*((volatile unsigned int *)0xE2900024)
    #define UBRDIV0 	*((volatile unsigned int *)0xE2900028)
    #define UDIVSLOT0	*((volatile unsigned int *)0xE290002C)
    
    /*
    ** UART0初始化
    */
    void uart_init()
    {
    	/*
    	** 配置GPA0_0为UART_0_RXD
    	** 配置GPA0_1为UART_0_TXD
    	*/
    	GPA0CON &= ~0xFF;
    	GPA0CON |= 0x22;
    
    	/* 8-bits/One stop bit/No parity/Normal mode operation */
    	ULCON0 = 0x3 | (0 << 2) | (0 << 3) | (0 << 6);
    
    	/* Interrupt request or polling mode/Normal transmit/Normal operation/PCLK/*/
    	UCON0 = 1 | (1 << 2) | (0 << 10);
    
    	/* 静止FIFO */
    	UFCON0 = 0;
    
    	/*
    	** 波特率计算:115200bps
    	** PCLK = 66MHz
    	** DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
    	** UBRDIV0 = 34 (DIV_VAL的整数部分)
    	** (num of 1's in UDIVSLOTn)/16 = 0.8
    	** (num of 1's in UDIVSLOTn) = 12
    	** UDIVSLOT0 = 0xDDDD (查表)
    	*/
    	UBRDIV0 = 34;
    	UDIVSLOT0 = 0xDDDD;
    }
    
    void uart_send_byte(unsigned char byte)
    {
    	while (!(UTRSTAT0 & (1 << 2)));	/* 等待发送缓冲区为空 */
    	UTXH0 = byte;					/* 发送一字节数据 */		
    }
    
    unsigned char uart_recv_byte()
    {
    	while (!(UTRSTAT0 & 1));	/* 等待接收缓冲区有数据可读 */
    	return URXH0;				/* 接收一字节数据 */		
    }
    
    void uart_send_string(char *str)
    {
    	char *p = str;
    	while (*p)
    		uart_send_byte(*p++);
    }


    main.c

    #define GPC0CON		*((volatile unsigned int *)0xE0200060)
    #define GPC0DAT		*((volatile unsigned int *)0xE0200064)
    
    void delay(volatile unsigned int t)
    {
    	volatile unsigned int t2 = 0xFFFF;
    	while (t--)
    		for (; t2; t2--);
    }
    
    int main()
    {
    	int byte;
    
    	GPC0CON &= ~(0xFF << 12);
    	GPC0CON |= 0x11 << 12;		// 配置GPC0_3和GPC0_4为输出
    	GPC0DAT &= ~(0x3 << 3);		// 熄灭LED1和LED2
    
    	uart_send_string("
    UART Test in S5PV210
    ");
    
    	while (1)
    	{
    		uart_send_string("
    1.LED1 Toggle
    ");
    		uart_send_string("
    2.LED2 Toggle
    ");
    		uart_send_string("
    Please select 1 or 2 to Toggle the LED
    ");
    		byte = uart_recv_byte();
    		uart_send_byte(byte);
    
    		if (byte == '1')
    			GPC0DAT ^= 1 << 3;		// 改变LED1的状态
    		else if (byte == '2')
    			GPC0DAT ^= 1 << 4;		// 改变LED2的状态
    	}
    	return 0;
    }


    Makefile

    uart.bin: start.o clock.o uart.o main.o
    	arm-linux-ld -Ttext 0xD0020010 -o uart.elf $^
    	arm-linux-objcopy -O binary uart.elf $@
    	arm-linux-objdump -D uart.elf > uart.dis
    	
    %.o : %.c
    	arm-linux-gcc -c $< -o $@
    %.o : %.S
    	arm-linux-gcc -c $< -o $@
    	
    clean:
    	rm *.o *.elf *.bin *.dis
    


    程序烧写步骤见前面章节。

    转载请注明来源:http://blog.csdn.net/zjhsucceed_329/

  • 相关阅读:
    C++中使用多线程
    hdu 4223 dp 求连续子序列的和的绝对值最小值
    hdu 1372 bfs 计算起点到终点的距离
    hdu 4217 线段树 依次取第几个最小值,求其sum
    心得
    hdu 1175 bfs 按要求进行搜索,是否能到达,抵消两个(相同)棋子
    hdu 4221 greed 注意范围 工作延期,使整个工作时间罚时最少的单个罚时最长的值
    hdu 2844 多重背包 多种硬币,每一种硬币有一点数量,看他能组成多少种钱
    uva LCDDisplay
    hdu 4218 模拟 根据一个圆点和半径画一个圆 注意半径要求
  • 原文地址:https://www.cnblogs.com/phisy/p/3371876.html
Copyright © 2011-2022 走看看