2440的UART初始化
一、准备知识
(1)波特率(bandrate),指的是串口通信的速率,也就是串口通信时每秒钟可以传输多少个二进制位。譬如每秒种可以传输9600个二进制位(传输一个二进制位需要的时间是1/9600秒,也就是104us),波特率就是9600.
(2)在电平信号时多少V代表1,多少V代表0不是固定的,取决于电平标准。譬如RS232电平中-3V~-15V表示1;+3~+15V表示0;TTL电平则是+5V表示1,0V表示0.
(3)DB9接口:DB9接口中有9根通信线,其中3根很重要,为GND、Tx、Rx,必不可少;剩余6根都是和流控有关的,现代我们使用串口都是用来做调试一般都禁用流控,所以这6根没用。
(4)串口的官方名称叫:universal asynchronous reciver and transmitter,通用异步收发器,英文缩写是uart,中文简称串口。
(5)自动流控(AFC:Auto flow control)
流控的目的是让串口通信非常可靠,在发送方速率比接收方快的时候流控可以保证发送和接收不会漏掉东西。
现在计算机之间有更好更高级(usb、internet)的通讯方式,串口已经基本被废弃了。现在串口的用途更多是SoC用来输出调试信息的。由于调试信息不是关键性信息、而且由于硬件发展串口本身速度已经相对慢的要死了,所以硬件都能协调发送和接收速率,因此流控已经失去意义了,所以现在基本都废弃了。
(6)IrDA模式及其用法
IrDA其实就是红外,红外就是红外线通信(电视机、空调遥控器就是红外通信的)。
红外通信的原理是发送方固定间隔时间向接收方发送红外信号(表示1或0)或者不发送红外信号(表示0或者1),接收方每隔固定时间去判断有无红外线信号来接收1和0.
分析可知,红外通信和串口通信非常像,都是每隔固定时间发送1或者0(判断1或0的物理方式不同)给接收方来通信。因此210就利用串口通信来实现了红外发送和接收。
2440的某个串口支持IrDA模式,开启红外模式后,我们只需要向串口写数据,这些数据就会以红外光的方式向外发射出去(当然是需要一些外部硬件支持的),然后接收方接收这些红外数据即可解码得到我们的发送信息。
二、寄存器设置
1. 设置引脚用于串口:根据原理图和参考手册设置GPH2,3用于TxD0, RxD0,并且为了将其保持为高电平,先设置其为上拉;
GPHCON &= ~((3<<4) | (3<<6));
GPHCON |= ((2<<4) | (2<<6));// GPH2,GPH3用作TXD0,RXD0
GPHUP &= ~((1<<2) | (1<<3)); /* 使能内部上拉 */
2.设置波特率(时钟和分频系数共同决定)
UCON0 = 0x00000005; /* PCLK,查询模式 */
UBRDIV0 = 26;
3.设置数据格式
ULCON0 = 0x03; // 8N1(8个数据位,无较验,1个停止位)
4.禁止FIFO
UFCON0 = 0x00; // 不使用FIFO
5.禁止流控
UMCON0 = 0x00; // 不使用流控
三、代码实验
1.Makefile
all:
arm-linux-gcc -c -o start.o start.S
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o init.o init.c
arm-linux-gcc -c -o serial.o serial.c
arm-linux-ld -Ttext 0 start.o main.o init.o serial.o -o led_on.elf
arm-linux-objcopy -O binary -S led_on.elf led_on.bin
clean:
rm *.bin *.o *.elf
2.start.S
.global _start
_start:
//关闭看门狗
ldr r0, =0
ldr r1, =0x53000000
str r0, [r1]
ldr sp, =4096
bl clock_init
bl main
b .
3.init.c
/*
* init.c: 进行一些初始化
*/
#include "s3c24xx.h"
void clock_init(void);
#define S3C2440_MPLL_400MHZ ((92<<12)|(1<<4)|(1<<0))
/*
* 对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV
* 有如下计算公式:
* S3C2440: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)
* 其中: m = MDIV + 8, p = PDIV + 2, s = SDIV
* 对于本开发板,Fin = 12MHz
* 设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:4:8,
* FCLK=400MHz,HCLK=100MHz,PCLK=50MHz
*/
void clock_init(void)
{
LOCKTIME = 0xFFFFFFFF; // 使用默认值即可
CLKDIVN = 0x05; // FCLK:HCLK:PCLK=1:4:8
/* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
__asm__(
"mrc p15, 0, r1, c1, c0, 0\n" /* 读出控制寄存器 */
"orr r1, r1, #0xc0000000\n" /* 设置为“asynchronous bus mode” */ //R1_nF:OR:R1_iA
"mcr p15, 0, r1, c1, c0, 0\n" /* 写入控制寄存器 */
);
MPLLCON = S3C2440_MPLL_400MHZ; /* 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
}
4.serial.c
#include "s3c24xx.h"
void uart0_init(void);
void putc(unsigned char c);
unsigned char getc(void);
int puts(const char *s);
#define TXD0READY (1<<2)
#define RXD0READY (1)
#define PCLK 50000000 // init.c中的clock_init函数设置PCLK为50MHz
#define UART_CLK PCLK // UART0的时钟源设为PCLK
#define UART_BAUD_RATE 115200 // 波特率
#define UART_BRD ((UART_CLK / (UART_BAUD_RATE * 16)) - 1)
/*
* 初始化UART0
* 115200,8N1,无流控
*/
void uart0_init(void)
{
GPHCON &= ~((3<<4) | (3<<6));
GPHCON |= ((2<<4) | (2<<6));// GPH2,GPH3用作TXD0,RXD0
GPHUP &= ~((1<<2) | (1<<3)); /* 使能内部上拉 */
ULCON0 = 0x03; // 8N1(8个数据位,无较验,1个停止位)
UCON0 = 0x05; // 查询方式,UART时钟源为PCLK
UFCON0 = 0x00; // 不使用FIFO
UMCON0 = 0x00; // 不使用流控
UBRDIV0 = UART_BRD; // 波特率为115200
}
/*
* 发送一个字符
*/
void putc(unsigned char c)
{
/* 等待,直到发送缓冲区中的数据已经全部发送出去 */
while (!(UTRSTAT0 & TXD0READY));
/* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */
UTXH0 = c;
}
/*
* 接收字符
*/
unsigned char getc(void)
{
/* 等待,直到接收缓冲区中的有数据 */
while (!(UTRSTAT0 & RXD0READY));
/* 直接读取URXH0寄存器,即可获得接收到的数据 */
return URXH0;
}
int puts(const char *s)
{
while (*s)
{
putc(*s);
s++;
}
}
5.main.c
#include "serial.h"
#include "s3c24xx.h"
void delay(void);
// 该函数要实现led闪烁效果
int main(void)
{
unsigned char c;
uart0_init(); // 波特率115200,8N1(8个数据位,无校验位,1个停止位)
// led初始化
GPFCON = 0x1500;
while (1)
{
putc('a');
// led亮
GPFDAT = ((0<<4) | (0<<5) | (0<<6));
// 延时
delay();
// led灭
GPFDAT = ((1<<4) | (1<<5) | (1<<6));
// 延时
delay();
}
return 0;
}
void delay(void)
{
unsigned int i = 200000;
while (i--);
}
6.s3c24xx.h
/* WOTCH DOG register */
#define WTCON (*(volatile unsigned long *)0x53000000)
/* SDRAM regisers */
#define MEM_CTL_BASE 0x48000000
#define SDRAM_BASE 0x30000000
/* NAND Flash registers */
#define NFCONF (*(volatile unsigned int *)0x4e000000)
#define NFCMD (*(volatile unsigned char *)0x4e000004)
#define NFADDR (*(volatile unsigned char *)0x4e000008)
#define NFDATA (*(volatile unsigned char *)0x4e00000c)
#define NFSTAT (*(volatile unsigned char *)0x4e000010)
/*GPIO registers*/
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
#define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)
#define GPFUP (*(volatile unsigned long *)0x56000058)
#define GPGCON (*(volatile unsigned long *)0x56000060)
#define GPGDAT (*(volatile unsigned long *)0x56000064)
#define GPGUP (*(volatile unsigned long *)0x56000068)
#define GPHCON (*(volatile unsigned long *)0x56000070)
#define GPHDAT (*(volatile unsigned long *)0x56000074)
#define GPHUP (*(volatile unsigned long *)0x56000078)
/*UART registers*/
#define ULCON0 (*(volatile unsigned long *)0x50000000)
#define UCON0 (*(volatile unsigned long *)0x50000004)
#define UFCON0 (*(volatile unsigned long *)0x50000008)
#define UMCON0 (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)
#define UTXH0 (*(volatile unsigned char *)0x50000020)
#define URXH0 (*(volatile unsigned char *)0x50000024)
#define UBRDIV0 (*(volatile unsigned long *)0x50000028)
/*interrupt registes*/
#define SRCPND (*(volatile unsigned long *)0x4A000000)
#define INTMOD (*(volatile unsigned long *)0x4A000004)
#define INTMSK (*(volatile unsigned long *)0x4A000008)
#define PRIORITY (*(volatile unsigned long *)0x4A00000c)
#define INTPND (*(volatile unsigned long *)0x4A000010)
#define INTOFFSET (*(volatile unsigned long *)0x4A000014)
#define SUBSRCPND (*(volatile unsigned long *)0x4A000018)
#define INTSUBMSK (*(volatile unsigned long *)0x4A00001c)
/*external interrupt registers*/
#define EINTMASK (*(volatile unsigned long *)0x560000a4)
#define EINTPEND (*(volatile unsigned long *)0x560000a8)
/*clock registers*/
#define LOCKTIME (*(volatile unsigned long *)0x4c000000)
#define MPLLCON (*(volatile unsigned long *)0x4c000004)
#define UPLLCON (*(volatile unsigned long *)0x4c000008)
#define CLKCON (*(volatile unsigned long *)0x4c00000c)
#define CLKSLOW (*(volatile unsigned long *)0x4c000010)
#define CLKDIVN (*(volatile unsigned long *)0x4c000014)
/*PWM & Timer registers*/
#define TCFG0 (*(volatile unsigned long *)0x51000000)
#define TCFG1 (*(volatile unsigned long *)0x51000004)
#define TCON (*(volatile unsigned long *)0x51000008)
#define TCNTB0 (*(volatile unsigned long *)0x5100000c)
#define TCMPB0 (*(volatile unsigned long *)0x51000010)
#define TCNTO0 (*(volatile unsigned long *)0x51000014)
#define GSTATUS1 (*(volatile unsigned long *)0x560000B0)
实验结果:led闪烁的同时,串口打印aaaaaaaaaaaaaaaa......参考:
朱老师课件
韦老师代码
上一篇: JZ2440裸机实验-点亮LED
下一篇: 浅谈单片机的数据输入和接收