第五站,我想对社会说——uart串口程序分析

来源:互联网 发布:淘宝店转让风险大吗 编辑:程序博客网 时间:2024/06/15 07:55
第五站,我想对社会说——uart串口程序分析
我们存在的价值,是得到这个世界的认可,是让世界认识你,知道你的存在,我们内心的故事,也需要向别人倾述,否则谁能轻易了解你?我们的苦闷也需要偶尔的牢骚,如果我们与世界失去了联系和交际,简直太过单调。那么,就让我们通过UART去倾听ARM的内心吧。
 
 
6410提供了四个独立的异步串行I/O端口,每个一步串行I/O端口通过终端或者直接存储器存取(DMA)模式来操作。换句话说就是UART通过产生中断或DMA请求在CPU和UART之间传输数据.
每个UART的通道包含了连个64字节收发FIFO存储器。
每个UART包含一个波特率发生器,发送器,接收器和控制单元,该波特率发生器由PCLK,ext_uclk0或ext_uclk1进行时钟控制。
发射器和接收器包含64字节的FIFO存储器和数据移位寄存器,发送数据之前,首先将数据写入FIFO存储器,然后复制到发送移位寄存器,通过发送数据的引脚(txdn)将数据发送,
同时,通过数据接收的引脚(rsdn)将接收到的数据从接收移位寄存器复制到FIFO存储器。这其中的复制,无需要我们人工干涉,硬件自动完成。

我们要做的,就只是设置好波特率等工作,然后将数据写进发送FIFO,硬件自动会拷贝数据到发送移位寄存器发送我们的数据,读数据只需要当接收完成我们读取接收FIFO中的数据就可以了。

regs.h:
#ifndef __REGS_H
#define __REGS_H

/******************uart****************/
#define GPACON (*(volatile unsigned int *)0x7F008000)
#define ULCON0        (*(volatile unsigned int *)0x7F005000)      //UART通道0行控制寄存器
#define UCON0        (*(volatile unsigned int *)0x7F005004)      //UART通道0控制寄存器
#define UFCON0        (*(volatile unsigned int *)0x7F005008)      //UART通道0FIFO控制寄存器
#define UMCON0        (*(volatile unsigned int *)0x7F00500C)      //UART通道0调制解调器(Modem)控制寄存器
#define UTRSTAT0       (*(volatile unsigned int *)0x7F005010)      //UART通道0发送/接收状态寄存器
#define UERSTAT0       (*(volatile unsigned int *)0x7F005014)      //UART通道0接收错误状态寄存器
#define UFSTAT0       (*(volatile unsigned int *)0x7F005018)      //UART通道0FIFO状态寄存器
#define UMSTAT0       (*(volatile unsigned int *)0x7F00501C)      //UART通道0调制解调器(Modem)状态寄存器
#define UTXH0        (*(volatile unsigned int *)0x7F005020)          //UART通道0发送缓冲寄存器
#define URXH0        (*(volatile unsigned int *)0x7F005024)           //UART通道0接收缓冲寄存器
#define UBRDIV0       (*(volatile unsigned int *)0x7F005028)           //UART通道0波特率分频寄存器
#define UDIVSLOT0      (*(volatile unsigned int *)0x7F00502C)      //UART通道0分频插槽寄存器
#define UINTP0       (*(volatile unsigned int *)0x7F005030)           //UART通道0中断处理寄存器
#define UINTSP0       (*(volatile unsigned int *)0x7F005034)           //UART通道0中断源处理器
#define UINTM0       (*(volatile unsigned int *)0x7F005038)           //UART通道0中断屏蔽寄存器


#endif

uart.c:
#include "common.h"
#include "regs.h"
#include <stdarg.h>
/*va_list
*va_start
*va_end
*va_arg
*/

/*检查上次数据是否发完,参考S3C6410手册P1096*/
#define TR_BUSY while(!(UTRSTAT0 & 2))  //检测UTRSTAT0的第二位是否为0,为0表示发送缓冲寄存器不为空,即有数据,表示发送正忙,咱还不能写数据到此寄存器需等待。
/*检查是否收到数据,参考S3C6410手册P1096*/
#define RC_BUSY     while(!(UTRSTAT0 & 1))  //检测UTRSTAT0的第一位是否为0,为0表示接收缓冲寄存器为空,即没有有效数据,此时不能读该寄存器获得接收数据,需等待。

void uart_init(void)
{
     /*设置GPA0-1为UART_com0功能,参考S3C6410手册P312*/
     GPACON &= ~(0xff);    
     GPACON |= 0x22;

     /*设置8N1,参考S3C6410手册P1091*/
     ULCON0 = 3;               //这里设置UART行控制器,行控制器用来选择操作模式,设定奇偶校验,设置每帧中停止位个数,数据位的个数等。
                              //具体设置请看6410数据手册UART章节,这里赋值为3,即设置为:普通操作模式,无校验,每帧一位停止位,数据位个数为8位(就由1-0位控制)
                             
     /*设置采用轮询模式,参考S3C6410手册P1092*/
     UCON0 |= (1 << 2) | (1 << 0); //这里就是设置第2位,第0位,这两位的设置是设置成轮询模式,其他位默认0,具体请看其他位的设置对应什么。
                                        //位11-10=00,表示使用PCLK作为UART波特率时钟源,位9=0,设置中断请求类型为脉冲,位8=0,设置接收中断请求类型为脉冲,
                                        //其他的请具体看手册吧
     /*把FIFO关掉*/
     UFCON0 = 0;
     UMCON0 = 0;
    
     /*配置波特率为115200,参考S3C6410手册P1101*/
     UBRDIV0 = 34;//34.8<--115200
     UDIVSLOT0 = 0xdfdd;//13<--0.8          //这里得到用16*0.8=12.8,四舍五入得到13,然后查看手册UART章节表UDIVSLOTn,找到对应13的值0xdfdd
}
波特率的设置过程:
UBRDIV0中的值决定串行Rx/Tx时钟波特率,具体计算如下图:

(可怜啊,这有是两幅截图呢,关于波特率的计算,来自于6410datasheetUART章节,请主动查看)


void uputchar(char c)
{
     TR_BUSY;
     /*把要发送的数据写到发送寄存器,参考S3C6410手册P1100*/
     UTXH0 = c;
}

char ugetchar(void)
{
     RC_BUSY;
     /*硬件会把收到的数据自动放到URXH0里,参考S3C6410手册P1100*/
     return URXH0;
}

void _uputs(char *buf)
{
     while(*buf != '\0'){
          uputchar(*buf);
          if(*buf == '\n'){
               uputchar('\r');
          }
          buf++;
     }    
}

void uputs(char *buf)
{
     _uputs(buf);
     uputchar('\n');    
     uputchar('\r');    
}

char *ugets(char *buf)
{
     char *save = buf;
     char c;
    
     while((c = ugetchar()) != '\r'){
          *buf = c;
          uputchar(c);
          buf++;
     }

     *buf = '\0';
     uputchar('\r');
     uputchar('\n');

     return save;
}

void itoa(unsigned int d, char *buf)
{
     int i;

     if(d < 10){
          buf[0] = d + '0';
          buf[1] = '\0';
          return;
     }    
     itoa(d / 10, buf);
     for(i = 0; buf[i] != '\0'; i++){
          ;
     }
     buf[i] = (d % 10) + '0';
     buf[i + 1] = '\0';
}

void xtoa(unsigned int d, char *buf)
{
     int i;

     if(d < 16){
          if(d < 10){
               buf[0] = d + '0';
               buf[1] = '\0';
          }else{
               buf[0] = d - 10 + 'a';
               buf[1] = '\0';
          }
          return;
     }
     xtoa(d / 16, buf);
     for(i = 0; buf[i] != '\0'; i++){
          ;
     }
     if((d % 16) < 10){
          buf[i] = (d % 16) + '0';
          buf[i + 1] = '\0';
     }else{
          buf[i] = (d % 16) - 10 + 'a';
          buf[i + 1] = '\0';
     }
}

/*%s %c %d %x*/
//uprintf("hello %d %c %x %s\n", 10, 'a', 0x100, "d");
//va_start 建立对应关系
//va_end 取消对应关系
//va_list 对应关系变量类型
//va_arg 根据对应关系取出相应的数据

int uprintf(const char *fmt, ...)
{
     va_list ap;
     char c;
     int d;
     char *s;
     char buf[64];

     va_start(ap, fmt);
     while(*fmt != '\0'){
          if(*fmt == '%'){
               fmt++;
               switch(*fmt){
                    case 'c':
                         c = va_arg(ap, int);
                         uputchar(c);
                         break;
                    case 'd':
                         d = va_arg(ap, int);
                         if(d < 0){
                              uputchar('-');
                              d = -d;

                         }
                         itoa(d, buf);                   
                         _uputs(buf);
                         break;
                    case 's':
                         s = va_arg(ap, char *);
                         _uputs(s);
                         break;
                    case 'x':
                         d = va_arg(ap, int);
                         xtoa(d, buf);
                         _uputs(buf);
                         break;
                    case '%':
                         break;
                    default:
                         break;
               }
          }else{
               uputchar(*fmt);
               if(*fmt == '\n'){
                    uputchar('\r');
               }
          }
          fmt++;
     }

     va_end(ap);
}

main.c:
#include "common.h"
#include "regs.h"

int main(int argc, char **argv)
{
     char c;
     char buf[1024];

     uart_init();
     c = ugetchar();
     uputchar(c);

     uputs("hello uputs...");    
    
     ugets(buf);
     uputs(buf);    

     uprintf("hello uprintf()\n");
     uprintf("hello %c %s\n", 'x', "ssssssssss");

     uprintf("abcd%d %c %s %x\n", 100, 'b', "hello uprintf", 0x100);

     return 0;
}




说明:
    串口绝对是个重要的东西,本站只是分析了串口初始化的过程,其实串口的还有一些地方没有讲到,那就在需要的时候多方资料学习。
 

关于本站的任何疑问,请来群交流,ES6 :180631429
入群请务必附加入群请求说明,因为防止广告号入群打广告,给志同道合的群友造成不必要的麻烦,影响我们的心情。
附加信息请包含以下关键字:学习,嵌入式,交流,ES,空间,CSDN,疯子,壳,蓝天,飞雪,骑士……
愿我们一起,共同进步。

原创粉丝点击