数据传输、充当控制台(即uboot启动的时候,通过串口输入输出数据进行控制)
串口通讯,分为同步通讯和异步通讯,我们通常使用的都是异步串口。通讯时,双方先约定好数据帧的格式,即波特率,数据位,停止位,奇偶校验位等。这是一个衡量通信速度的参数。它表示每秒钟传送的bit的个数。例如300波特表示每秒钟发送300个bit。常用的波特率有38400,115200。
起始位:当线路空闲时候,电平为高。一旦检测到一个下降沿,则视为一个起始位。然后接收方按照约定好的格式,接收这一帧数据。
数据位:一帧中实际有效数据的位数。
停止位:表示这帧数据的结束。
校验位:用于检测数据传输是否正确的位。
我们通常使用的RS232的9帧串口,其中最为重要的是2,3,5脚
2 :RXD:接收数据
3 :TXD:发送数据
5 :GND:接地
配置GPIO为串口接收发送模式,看上面的图可知为GPA0,GPA1.
#define GPACON (*((volatile unsigned short *)0x7F008000)) //端口A配置寄存器
GPACON &= ~0xff;
GPACON |= 0x22;
#define ULCON0 (*((volatile unsigned long *)0x7F005000)) //UART0通道行控制寄存器
ULCON0 = 0b11;
#define UCON0 (*((volatile unsigned long *)0x7F005004))
UCON0 = 0b0101;
根据上图,可以得知波特率的计算公式,并且计算结果UBRDIVn保留整数位,UDIVSLOTn保留小数位,
#define UBRDIV0 (*((volatile unsigned short *)0x7F005028)) //波特率分频寄存器
#define UTRSTAT0 (*((volatile unsigned long *)0x7F005010)) //UART 通道0 发送/接收状态寄存器
#define PCLK 66500000
#define BAUD 115200
UBRDIV0 =(int)(PCLK/(BAUD*16)-1); //UBRDIV0保存该公式计算后的整数部分
UDIVSLOT0 = 0x0; //UDISLOT0=保存该公式计算后的小数部分*16
#define UTXH0 (*((volatile unsigned char *)0x7F005020)) //UART 通道0 发送缓冲寄存器
#define UTRSTAT0 (*((volatile unsigned long *)0x7F005010))
void putc(unsigned char ch)
{ while (!(UTRSTAT0 & (1<<2))); UTXH0 = ch; }
buff空了,说明以前的数据发送走了,然后将要发送的数据送入寄存器
根据上图可以得知,如果第0位为0,则说明没有数据,因此需要等待
而接收到的数据会放到URXH0这个寄存器里面,因此需要从这个寄存器里面取出数据
unsigned char getc(void)
{
unsigned char ret;
while (!(UTRSTAT0 & (1<<0)));
// 取数据
ret = URXH0;
return ret;
}
实现了上面的puts和gets函数,接下来就要实现大家常用的printf和scanf函数。
1.将变参转化为字符串
va_start(args,fmt); //利用fmt得到变参的个数,然后把变参放到args里面
vsprintf((char *)outbuf, fmt, args); //将变参转换为字符串
va_end(); //结束转换
for(i=0;i< strlen((char *)outbuf); i++) //一个字符一个字符输出
{
putc(outbuf[i]);
}
1. 获取输入的字符串
while (1)
{
c = getc();
if ((c==0x0d) || (c==0x0a))
{
inbuf[i] = '\n';
break;
}
else
{
inbuf[i++] = c;
}
}
2. 格式转化
va_start(args, fmt);
vsscanf((char *)inbuf,fmt,args);
va_end(args);
贴上代码:
uart.c
/******************************************** *file name: uart.c *author : stone *date : 2016.7.5 *function : 串口相关 *********************************************/
#define GPACON (*((volatile unsigned short *)0x7F008000)) //端口A配置寄存器
#define ULCON0 (*((volatile unsigned long *)0x7F005000)) //UART0通道行控制寄存器
#define UCON0 (*((volatile unsigned long *)0x7F005004)) //UART0通道控制器
#define UBRDIV0 (*((volatile unsigned short *)0x7F005028)) //波特率分频寄存器
#define UTRSTAT0 (*((volatile unsigned long *)0x7F005010)) //UART 通道0 发送/接收状态寄存器
#define UTXH0 (*((volatile unsigned char *)0x7F005020)) //UART 通道0 发送缓冲寄存器
#define URXH0 (*((volatile unsigned char *)0x7F005024)) //UART 通道0 接收缓冲寄存器
#define UDIVSLOT0 (*((volatile unsigned short *)0x7F00502C)) //UART 通道0 分频插槽寄存器
#define PCLK 66500000
#define BAUD 115200
void uart_init()
{
//配置引脚功能
GPACON &= ~0xff;
GPACON |= 0x22;
//设置数据格式 停止位、校验位、数据位
ULCON0 = 0b11;
//设置工作模式 工作在轮询模式(简单)
UCON0 = 0b0101;
//设置波特率
UBRDIV0 =(int)(PCLK/(BAUD*16)-1); //UBRDIV0保存该公式计算后的整数部分
UDIVSLOT0 = 0x0; //UDISLOT0=保存该公式计算后的小数部分*16
}
//发送
void putc(unsigned char ch)
{
while (!(UTRSTAT0 & (1<<2)));
UTXH0 = ch;
}
//接收
unsigned char getc(void)
{
unsigned char ret;
while (!(UTRSTAT0 & (1<<0))); //UTRSTAT0为1时表明里面有数据 等待
// 取数据
ret = URXH0;
if ( (ret == 0x0d) || (ret == 0x0a) )
{
putc(0x0d);
putc(0x0a);
}
else
putc(ret);
return ret;
}
printf.c
/******************************************** *file name: printf.c *author : stone *date : 2016.7.5 *function : 实现数据的收发 *********************************************/
#include "vsprintf.h"
unsigned char outbuf[1024];
unsigned char inbuf[1024];
int printf(const char* fmt, ...)
{
va_list args;
int i;
//1.将变参转化为字符串
va_start(args,fmt); //利用fmt得到变参的个数,然后把变参放到args里面
vsprintf((char *)outbuf, fmt, args); //将变参转换为字符串
va_end(); //结束转换
//2. 打印字符串到串口
for(i=0;i< strlen((char *)outbuf); i++)
{
putc(outbuf[i]);
}
return i;
}
int scanf(const char* fmt, ...)
{
unsigned char c;
int i = 0;
va_list args;
//1. 获取输入的字符串
while (1)
{
c = getc();
if ((c==0x0d) || (c==0x0a))
{
inbuf[i] = '\n';
break;
}
else
{
inbuf[i++] = c;
}
}
//2. 格式转化
va_start(args, fmt);
vsscanf((char *)inbuf,fmt,args);
va_end(args);
return i;
}
菜鸟一枚,如有错误,多多指教。。。