10.串口

10.串口

串口框图:

UART_URXD寄存器保存着串口接收到的数据。

UART_UTDX寄存器为发送数据寄存器,如果需要通过串口发送数据,只需要将数据写入到UART_UTXD寄存器里面、

UART_UCR1~UART_UCR4寄存器都是串口控制寄存器,

UART_UCR1[0]是UART的使能位,为1使能

UART_UCR1[4]:自动检测波特率使能位,为1使能波特率自动检测

UART_UCR2[0]:软件复位位,为0的时候复位UART。

UART_UCR2[2]:发送使能位,设置为1

UART_UCR2[5]:设置数据位 0 表示7位数据位 1表示 8位数据位

UART_UCR2[6]:设置停止位 0表示1位停止位 1表示2位停止位

UART_UCR2[7]:表示奇偶校验位,为0是偶校验、为1为奇校验

UART_UCR2[8] : 校验使能位,为0关闭校验位

UART_UCR3的[2]必须为1!!!

UART_UFCR寄存器的[7-9]设置分频值,时钟源为PLL3 我们设置为6-1即6分频 分频后为80Mhz

UART前面还可以对时钟源进行设置,保持默认即可。

CCM_CSCDR寄存器UART_CLK_SEL位可以对UART的时钟源进行选择 0:PLL3经过6分频(前面设置的)后的80Mhz以及 1:OSC(24Mhz)时钟源

CCM_CSCDR寄存器UART_CLK_PODF位控制预分频值,一半设置为1分频

UART_UFCR、UART_UBIR、UART_UBMR这三个寄存器可以配置串口的波特率

UART_USR2寄存器的bit0为1 的时候表示有数据可以读取。bit3为1的时候表示数据发送完成。

bsp_uart.h

c 复制代码
#ifndef __BSP_UART_H
#define __BSP_UART_H
#include "imx6ul.h"
void uart_init(void);
void uart_disable(UART_Type *base);
void uart_enable(UART_Type *base);
void uart_softReset(UART_Type *base);
void uart_io_init(void);
void putc(unsigned char c);
unsigned char getc(void);
void puts(char *str);
void uart_setbaudrate(UART_Type *base, unsigned int baudrate, unsigned int srcclock_hz);
#endif

  

bsp_uart.c

c 复制代码
#include "imx6ul.h"
#include "bsp_led.h"
#include "bsp_delay.h"
#include "bsp_gpio.h"
#include "bsp_uart.h"

void uart_init(void){
    uart_io_init();
    uart_disable(UART1);
    uart_softReset(UART1);

    //配置uart1
    UART1->UCR1 = 0;
    
    //配置uart的数据位
    UART1->UCR2 |=  (1<<1)|(1<<2)|(1<<5)|(1<<14);

    //初始化
    UART1->UCR3 |= (1<<2);

    /*
     * 设置UART的UCR1寄存器,关闭自动波特率
     * bit14: 0 关闭自动波特率检测,我们自己设置波特率
	 */
    UART1->UCR1 &= ~(1<<14);
    //设置波特率

    #if 0
    UART1->UFCR &=~ (7<<7); //先清零
    UART1->UFCR |= (5<<7);  //设置为一分频
    UART1->UBIR = 71;
    UART1->UBMR = 3124;
    #endif

    uart_setbaudrate(UART1,115200,80000000);
    //使能串口
    uart_enable(UART1);
}

void uart_disable(UART_Type *base){

    base->UCR1 &=~(1<<0);
}

void uart_enable(UART_Type *base){

    base->UCR1 |= (1<<0);
}
void uart_softReset(UART_Type *base){
    base->UCR2 &=~ (1<<0);
    while ((base->UCR2 & 0x1)== 0);
}
void uart_io_init(void){

    //配置IO复用功能
    IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX,0);	
    IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX,0);	


	IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX,0x10B0);
    IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX,0x10B0);	
}

void putc(unsigned char c){
    while(((UART1->USR2 >>3) & 0x1) == 0);//等待上次发送完成
    UART1->UTXD = c & 0xff;

}

unsigned char getc(void){
    while (((UART1->USR2) & 0x1) == 0) ; //等待有数据可以读取
    return UART1->URXD;
}


void puts(char *str){
    char *p = str;
    while (*p)
    {
       putc(*p++);
    }

}

//由官方库函数提供。
/*
 * @description 		: 波特率计算公式,
 *    			  	  	  可以用此函数计算出指定串口对应的UFCR,
 * 				          UBIR和UBMR这三个寄存器的值
 * @param - base		: 要计算的串口。
 * @param - baudrate	: 要使用的波特率。
 * @param - srcclock_hz	:串口时钟源频率,单位Hz
 * @return		: 无
 */
void uart_setbaudrate(UART_Type *base, unsigned int baudrate, unsigned int srcclock_hz)
{
    uint32_t numerator = 0u;		//分子
    uint32_t denominator = 0U;		//分母
    uint32_t divisor = 0U;
    uint32_t refFreqDiv = 0U;
    uint32_t divider = 1U;
    uint64_t baudDiff = 0U;
    uint64_t tempNumerator = 0U;
    uint32_t tempDenominator = 0u;

    /* get the approximately maximum divisor */
    numerator = srcclock_hz;
    denominator = baudrate << 4;
    divisor = 1;

    while (denominator != 0)
    {
        divisor = denominator;
        denominator = numerator % denominator;
        numerator = divisor;
    }

    numerator = srcclock_hz / divisor;
    denominator = (baudrate << 4) / divisor;

    /* numerator ranges from 1 ~ 7 * 64k */
    /* denominator ranges from 1 ~ 64k */
    if ((numerator > (UART_UBIR_INC_MASK * 7)) || (denominator > UART_UBIR_INC_MASK))
    {
        uint32_t m = (numerator - 1) / (UART_UBIR_INC_MASK * 7) + 1;
        uint32_t n = (denominator - 1) / UART_UBIR_INC_MASK + 1;
        uint32_t max = m > n ? m : n;
        numerator /= max;
        denominator /= max;
        if (0 == numerator)
        {
            numerator = 1;
        }
        if (0 == denominator)
        {
            denominator = 1;
        }
    }
    divider = (numerator - 1) / UART_UBIR_INC_MASK + 1;

    switch (divider)
    {
        case 1:
            refFreqDiv = 0x05;
            break;
        case 2:
            refFreqDiv = 0x04;
            break;
        case 3:
            refFreqDiv = 0x03;
            break;
        case 4:
            refFreqDiv = 0x02;
            break;
        case 5:
            refFreqDiv = 0x01;
            break;
        case 6:
            refFreqDiv = 0x00;
            break;
        case 7:
            refFreqDiv = 0x06;
            break;
        default:
            refFreqDiv = 0x05;
            break;
    }
    /* Compare the difference between baudRate_Bps and calculated baud rate.
     * Baud Rate = Ref Freq / (16 * (UBMR + 1)/(UBIR+1)).
     * baudDiff = (srcClock_Hz/divider)/( 16 * ((numerator / divider)/ denominator).
     */
    tempNumerator = srcclock_hz;
    tempDenominator = (numerator << 4);
    divisor = 1;
    /* get the approximately maximum divisor */
    while (tempDenominator != 0)
    {
        divisor = tempDenominator;
        tempDenominator = tempNumerator % tempDenominator;
        tempNumerator = divisor;
    }
    tempNumerator = srcclock_hz / divisor;
    tempDenominator = (numerator << 4) / divisor;
    baudDiff = (tempNumerator * denominator) / tempDenominator;
    baudDiff = (baudDiff >= baudrate) ? (baudDiff - baudrate) : (baudrate - baudDiff);

    if (baudDiff < (baudrate / 100) * 3)
    {
        base->UFCR &= ~UART_UFCR_RFDIV_MASK;
        base->UFCR |= UART_UFCR_RFDIV(refFreqDiv);
        base->UBIR = UART_UBIR_INC(denominator - 1); //要先写UBIR寄存器,然后在写UBMR寄存器,3592页 
        base->UBMR = UART_UBMR_MOD(numerator / divider - 1);
        //base->ONEMS = UART_ONEMS_ONEMS(srcclock_hz / (1000 * divider));
    }

}
void raise(int sig_nr){


}

mian.c

c 复制代码
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_uart.h"

int main(void){
    int_Init(); //中断初始化必须要开头
    imx6u_clkinit();
    delay_init();
    uart_init();
    clk_enable();
   
    while (1)
    {
        puts("请输出一个字符");
        a = getc();
        putc(a);
        puts("\r\n");
        puts("您输入的字符为:");
		putc(a);
		puts("\r\n\r\n");
       
    }
    return 0;
}
  • putc()函数为内置函数,要使用它需要在编译时加上 -fno-builtin

修改Makefile

makefile 复制代码
$(SOBJS) : obj/%.o : %.S
	$(CC) -Wall -nostdlib -fno-builtin -c -O2  $(INCLUDE) -o $@ $<

$(COBJS) : obj/%.o : %.c
	$(CC) -Wall -nostdlib -fno-builtin -c -O2  $(INCLUDE) -o $@ $<

即可编译成功。

移植官方stdio,重写printf()函数

  • 编译 C 文件的时候添加了选项"-Wa,-mimplicit-it=thumb",否则的话会有如下类似的错误提示:thumb conditional instruction should be in IT block -- `addcs r5,r5,#65536

将官方stdio文件夹放置工程下,需要提供上面两个函数putc() 、getc()

添加头文件路径

然后就可以使用c语言的标准库函数进行格式化输入和输出了。

出现乱码需要检查,编码格式和波特率

移植的printf()禁止使用浮点计算和输出

相关推荐
Lzc7747 小时前
Linux网络的HTTPS
linux·https
我爱钱因此会努力8 小时前
ansible自动化运维入门篇
linux·运维·服务器·centos·自动化·ansible
腾飞的信仰8 小时前
为什么有的mcu烧录的时候是用hex,有的是用bin
单片机
---学无止境---9 小时前
Linux中系统调用sys_symlink和sys_unlink函数的实现
linux
代码程序猿RIP9 小时前
【Etcd 】Etcd 详解以及安装教程
linux·数据库·etcd
Rotion_深9 小时前
单片机 看门狗的作用
单片机·嵌入式硬件
tb_first10 小时前
Linux入门1(2/2)
linux
cellurw10 小时前
Day72 传感器分类、关键参数、工作原理与Linux驱动开发(GPIO/I²C/Platform/Misc框架)
linux·c语言·驱动开发
NextZeros10 小时前
基于CentOS安装LNMP
linux·centos