打印
[Kinetis]

KL25Z开发板学习记录:简单的串口操作UART0

[复制链接]
1616|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
小狗爱吃骨头|  楼主 | 2015-11-28 10:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
首先,我们应该先对UART0有一个简单的认识。参考手册的第39章对应这部分内容。我们不妨对照着固件库里面的代码对常用的寄存器做介绍。把固件库里面的UART0的初始化代码找出来。对应到init_board()函数,可以看到,在这个函数的最后,是对UART0的引脚复用的设置和UART0寄存器的设置,也就是这两句话:
    BSP_ConfigPinForUART(BSP_UART_DEBUG_INSTANCE);   // 引脚复用
    UART0_ConfigTransfer(&mDbgUartConfigStruct);        // 设置寄存器
跳转到第一个函数的定义,可以看到,这个函数并不完整,只是对UART0的情况作了处理,将PA的1,2管脚作为了UART0的发送和接收管脚,代码如下:
    case 0U: /* UART0. */
            PORTA->PCR[1] = PORT_PCR_MUX(2); /* UART0_RX. */
            PORTA->PCR[2] = PORT_PCR_MUX(2); /* UART0_TX. */
            break;


相关帖子

沙发
小狗爱吃骨头|  楼主 | 2015-11-28 10:50 | 只看该作者
查询引脚复用图,可以看到,PA的1,2管脚的ALT2正是串口的发送接收功能,如图所示。
第二个函数的参数是一个指向结构体的指针,这个结构体封装了设置UART所需要的波特率和系统时钟。UART0_ConfigTransfer()函数就利用这个结构体传进来的数值进行设置,主要是进行了波特率的设置和数据传输格式的设置。这部分代码已经有了注释,大家依照手册来看就可以了。
bool UART0_ConfigTransfer(const UART_Config_T *configPtr)
{
    uint16_t sbr_val;
    /* Disable the Rx and Tx.  设置寄存器之前先关闭RX和TX*/
    UART0->C2 &= ~(UART0_C2_TE_MASK | UART0_C2_RE_MASK);
   
    /* configure uart1 for 8-bit mode , no parity */
    UART0->C1 = 0U;
    /* calculate the sbr value. 通过BDH和BDL设置波特率 */
    sbr_val = (configPtr->BusClkHz >> 4)/configPtr->Baudrate;
    UART0->BDH = (uint8_t)(((0x1F00 & sbr_val) >> 8)&UART0_BDH_SBR_MASK);
    UART0->BDL = (uint8_t)(sbr_val & UART0_BDL_SBR_MASK);
    UART0->C3 = 0U;
    UART0->S1 = 0x1FU;
    UART0->S2 = 0U;
   
    /* enable the tx and rx  使能RX和TX*/
    UART0->C2 |= (UART0_C2_TE_MASK | UART0_C2_RE_MASK);
    return true;
}


使用特权

评论回复
板凳
小狗爱吃骨头|  楼主 | 2015-11-28 10:50 | 只看该作者
串口的初始化已经完成了,我们分析一下对串口的接受发送是怎么实现的。串口的发送和接收的数据会被送到UARTx->D里面进行缓存,等待读取或者发送。下面几个函数就是接收和发送的操作,我把它们加上了注释。
// 将待发送的字节数据送入到UARTx->D
void UART0_PutTxData(uint8_t txData)
{
        UART0->D = txData;
}
// 通过查询UARTx->S1寄存器的TDRE位判断发送数据寄存器是否为空
bool UART0_IsTxBufferEmpty(void)
{
        return ( 0U != (UART0->S1 & UART0_S1_TDRE_MASK) );
}
// 上面两个函数的综合,等待发送数据寄存器为空之后,将字节数据送入
void UART0_PutTxDataBlocking(uint8_t txData)
{
        while (!UART0_IsTxBufferEmpty() ) {}
        UART0_PutTxData(txData);
}
// 读接收寄存器中的一字节数据
uint8_t UART0_GetRxData(void)
{
        return (uint8_t)(UART0->D);
}
// 通过读S1的RDRF位判断是否已满(接收到了数据)
bool UART0_IsRxBufferFull(void)
{
        return (0U != (UART0->S1 & UART0_S1_RDRF_MASK) );
}
// 上面两个的综合,当接收到数据时,读一个字节的数据
uint8_t UART0_GetRxDataBlocking(void)
{
        while (!UART0_IsRxBufferFull() ) {}
        return UART0_GetRxData();
}

使用特权

评论回复
地板
小狗爱吃骨头|  楼主 | 2015-11-28 10:51 | 只看该作者
再说一句,在学习C语言的时候,我们知道有一个实现了标准输入输出的库文件stdio.h,里面实现了printf函数,可以将一些字符之类的显示到控制台上,而这里,利用上面的串口收发数据的函数重写一些函数,就可以实现printf向电脑的上位机写数据了!具体还请参考固件库里面的stdio_adapter.c文件。现在,利用这些函数,我们就可以实现自己的一些功能了。我们将main函数修改如下:
uint8_t buff = 0;
int sum = 0;
int main (void)
{
        /* 初始化板子 */
        init_board ();
        // 设置为输出
        GPIO_SetPinDir (BSP_GPIO_LED_RED_PORT , BSP_GPIO_LED_RED_PIN , true);
        // 设置为高电平,灯不导通
        GPIO_SetPinLogic (BSP_GPIO_LED_RED_PORT , BSP_GPIO_LED_RED_PIN , true);
        while (1)
        {
                if (UART0_IsRxBufferFull())   // 不停地轮询标志位
                {
                        buff = UART0_GetRxData();     // 读数据,这一操作会使得标志位清零
                        printf("Character Received: %c   ", buff);   // 向上位机发送
                        printf("Total Characters Received: %d\n", ++sum);
                        // 灯闪烁
                        GPIO_TogglePinLogic(BSP_GPIO_LED_RED_PORT, BSP_GPIO_LED_RED_PIN);  
                }
        }
}

使用特权

评论回复
5
小狗爱吃骨头|  楼主 | 2015-11-28 10:53 | 只看该作者
我们进行下载验证
在下一个帖子中,将讨论如何用中断实现这一功能。

串口.pdf

255.81 KB

使用特权

评论回复
6
Mancherstun| | 2015-11-28 15:18 | 只看该作者
仔细看了这个程序,用的是中断方式
发送和接收能同时用中断吗

使用特权

评论回复
7
李香兰| | 2015-11-28 17:08 | 只看该作者
串口和USB结合起来就好了

使用特权

评论回复
8
FSL_TICS_ZJJ| | 2015-11-30 10:50 | 只看该作者
感谢楼主的资料分享!

使用特权

评论回复
9
Messi1999| | 2015-11-30 12:50 | 只看该作者
李香兰 发表于 2015-11-28 17:08
串口和USB结合起来就好了

这个能结合起来啊,就是虚拟串口啊

使用特权

评论回复
10
小狗爱吃骨头|  楼主 | 2015-11-30 19:04 | 只看该作者
正在把uart0和USB连一块做一个虚拟的串口,给了我很大的提示

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

28

主题

286

帖子

0

粉丝