您的位置 首页 嵌入式

第4课:UART串口编程

首先明确一点:我们学习的串口是异步串口。在传输时,他们各自有各自的时钟。就是我们说的波特率。我们学习的RS232与UART的区别是,UART使…

首要清晰一点:咱们学习的串口是异步串口。在传输时,他们各自有各自的时钟。便是咱们说的波特率。

咱们学习的RS232与UART的差异是,UART运用规范的TTL/COMS电平 进过一个芯片使它的凹凸电平从TTL中0与3.3V 变成了 低电平5v到15v

高电平-3v到-12v。

首要说一下串口的数据帧格局。它由一个开端位,数据位,校验位和中止位组成。

平常数据处于1状况。

当要开端发送时,从UART改动TxD数据变成0状况1个位的时刻,在承受端到0之后的1.5位的时刻,接纳端开端承受数据。

数据位分为5,6,7,8。四种类型的数据位。之后便是校验位站1位,能够设置也能够不设置。最终的是中止位。能够是1位,1.5位,2位。这个是高电平1。

UART能够用中止或DMA来作业。它有3个独自的通道。它由4部分组成,发送器,接纳器,波特率发生器,操控逻辑组成。

这些部分的设置都是经过寄存器来完成的。

发送的进程是这样的,UART只能经过shifter一位一位的来发数据。它先把要发的数据放到它的缓存FIFO里,当然缓存也能够撤销。然后放入shifter里边来发出去。承受也是相同的。经过缓存来承受,然后再经过承受的shifter来接。

详细继电器的设置主要由以下几个:

ULCON 逻辑数据桢格局操控器

UCON 串口的操控继电器

UFCON FIFO操控寄存器

UMCON 串口MODEN操控器 (能够操控AFC 主动流操控)

以下是状况寄存器,用来确认状况的,比如说shifter发送器的状况,接纳器的状况。

UTRSTAT 承受发送操控器

UERSTAT 过错状况寄存器

UFSTAT FIFO状况寄存器

最终一个独自的设置寄存器,它用来设置波特率

UBRDIV 波特率发生器

以下来写个简略的串口比如。

它不运用FIFO 中止 而直接用shifter收发,选用轮询的方法来检测数据是否发送或被承受。然后经过minicom向开发板发送1表明亮灯,发送2表明熄灯。

文件总共是7个 一个crt0.s main.c addr.h uart.h uart.c uart.lds makefile

crt0.s 是封闭watchdog 并跳转到mian 之后用个deadloop。

.text
.globl _start
_start:
ldrr0, =0x53000000 @ WATCHDOG close
movr1, #0x0
strr1, [r0]
ldr sp, =1024*4 @set stack,but the capitcy of cache is only 4k

bl main
halt_loop:
b halt_loop

第2个是addr.h用来写寄存器的宏界说。

#ifndef ADDR_H
#define ADDR_H
#define GPECON (*(volatile unsigned int *)0x56000040)
#define GPEDAT (*(volatile unsigned int *)0x56000044)

#define GPE12_out (1<<(12*2))
#define GPE13_out (1<<(13*2))

#define GPHCON (*(volatile unsigned int *)0x56000070)
#define GPHUP (*(volatile unsigned int *)0x56000074)
#define ULCON0 (*(volatile unsigned int *)0x50000000)
#define UCON0 (*(volatile unsigned int *)0x50000004)
#define UFCON0 (*(volatile unsigned int *)0x50000008)
#define UMCON0 (*(volatile unsigned int *)0x5000000C)
#define UTRSTAT0 (*(volatile unsigned int *)0x50000010)
#define UFSTAT0 (*(volatile unsigned int *)0x50000018)
#define UTXH0 (*(volatile unsigned int *)0x50000020)
#define URXH0 (*(volatile unsigned int *)0x50000024)
#define UBRDIV0 (*(volatile unsigned int *)0x50000028)

#endif

第3个文件来写uart.h,这是个咱们的功用

#ifndef UART_H
#define UART_H
void uart_init(); //初始化继电器

void uart_write(char *a); //串口写一行

void uart_read(char *a,int n);//串口读n个字

void uart_read_line(char *a); //读一行

void led_on(); //开灯

void led_off();//关灯
#endif

第4个文件详细来写uart.C

#include”uart.h”
#include”addr.h”
#define UART_CLK 50000000 //咱们用的是PCLK 50MHz
#define UART_BAUD_RATE 115200 //比特率是115200
#define UART_BRD (int)(UART_CLK/(UART_BAUD_RATE *16))-1 //计算公式的宏
void uart_init()
{
GPHCON |=0xa0;//这个是TXD0与RXD0的设置,他们用的是GPH2和3复用的特别
GPHUP = 0x0c;//功用,所以还要在这设置上拉电阻,以差异凹凸电平的。
ULCON0 = 0x3; //桢格局的设置8个数据位,无校验
UCON0 = 0x5;//挑选的是中止与轮询形式
UFCON0 = 0;//不设FIFO
UMCON0 = 0;//不设AFC
UBRDIV0 = UART_BRD; //设置波特率
}

void uart_write(char *a)
{
do{
while(!(UTRSTAT0&2)); //UTRSTAT0的第2位是1的话表明发送数据的shifter内的数据现已被发送了,现在数据为空。假如里边的数据没有空的话!(U&2)会一向是1,形成一向循环,知道呈现UTRSTAT0第2位为1的状况。

UTXH0 = *(a++); //发送寄存器只能一次最多发8位
}
while(*a!=\0);
}

void uart_read(char *a,int n)
{
do{

while(!(UTRSTAT0&1));//第1位为1表明shifter内的数据现已有了,能够读了,假如为0的话将一向循环,知道有数据可读。
*(a++) = (char)URXH0;
n–;
}
while(n>0);
}

void uart_read_line(char *a)
{
do{

while(!(UTRSTAT0&1));
*(a++) = URXH0;
}
while(*a!=\0);
}

void led_on()
{
GPEDAT = 0;
}

void led_off()
{
GPEDAT = (3<<12);
}

第5个文件main.c文件

#include”addr.h”
#include”uart.h”

int main()
{
char *t = “Welcome to bootloader…\r\n”;//这儿只能用指针来传递,指针指向常量字符串的首地址传入。
char *t1 = “press 1 to light loop on\r\n”;
char *t2 =”press 2 to light loop off\r\n”;
char *t3 =”please input your choice\r\n”;
char r[10] ;//这儿指针必须用数组来分配,一个没有malloc函数。
GPECON = GPE12_out|GPE13_out;

uart_init();
uart_write(t);
uart_write(t1);
uart_write(t2);
uart_write(t3);
while(1){
uart_read(r,1);
UTXH0 = *r;//这儿是为了回显
switch(*r){
case 1:led_on();break;
case 2:led_off();break;
}
}
return 0;
}

第6个衔接文件

SECTIONS {
. = 0x00;
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}
最终介绍下makefile比较好的写法。

SRC := $(wildcard *.c) //设定直接变量SRC,$(wildcard )表明运用通配符
OBJC := $(patsubst %.c,%.o,$(SRC)) //表明把SRC里的值是.c结束的换成.o结束的成果保存到OBJC中

uart.bin:uart.elf
arm-linux-objcopy -O binary -S $^ $@//表明$@方针文件$^一切依靠
arm-linux-objdump -D -m arm $^ > uart.dis
uart.elf:crt0.o $(OBJC)
arm-linux-ld -T uart.lds $^ -o $@
%.o:%.c //恣意.o的依靠为.c
arm-linux-gcc -c $^ -o $@
%.o:%.s
arm-linux-gcc -c $^ -o $@

clean:
rm -f uart.bin uart.dis uart.elf uart.o crt0.o main.o

然后用jtag烧入0x0内部SRAM的4k容量内,并在minicom里输入数据来操控led

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qianrushi/274788.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部