历史上的今天
返回首页

历史上的今天

今天是:2025年01月19日(星期日)

正在发生

2020年01月19日 | STM32F10x 利用环形缓冲区的串口驱动程序

2020-01-19 来源:eefocus

这次讲讲利用串口收发中断来进行串口通讯。STM32 上为每个串口分配了一个中断。也就是说无论是发送完成还是收到数据或是数据溢出都产生同一个中断。程序需在中断处理函数中读取状态寄存器(USART_SR)来判断当前的是什么中断。下面的中断映像图给出了这些中断源是如何汇合成最终的中断信号的。图中也给出了如何控制每一个单独的中断源是否起作用。

另外,Cortex-M3 内核中还有个NVIC,可以控制这里的中断信号是否触发中断处理函数的执行,还有这些外部中断的级别。关于NVIC 可以参考《ARM CortexM3 权威指南》,里面讲解的非常详细。


简单的说,为了开启中断,我们需要如下的代码:


NVIC_InitTypeDef NVIC_InitStructure;  

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;  

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  

NVIC_Init(&NVIC_InitStructure);  

  

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启接收中断  

USART_ITConfig(USART1, USART_IT_TXE, ENABLE); // 开启发送中断  

这里多说一句,串口的发送中断有两个,分别是:


l发送数据寄存器空中断(TXE)

l发送完成中断(TC)

一般来说我们会使用发送数据寄存器空中断,用这个中断发送的效率会高一些。


中断处理函数的框架如下,如果检测到错误就清除错误,收到数了就处理。发完当前数据了就发下一个。


void USART1_IRQHandler(void)  

{  

    unsigned int data;  

  

    if(USART1->SR & 0x0F)   

    {  

        // See if we have some kind of error, Clear interrupt     

        data = USART1->DR;  

    }  

    else if(USART1->SR & USART_FLAG_RXNE) //Receive Data Reg Full Flag  

    {    

        data = USART1->DR;  

        // 对收到的数据进行处理,或者干些其他的事    

    }  

    else if(USART1->SR & USART_FLAG_TXE)   

    {  

        { // 可以发送数据了,如果没有数据需要发送,就在这里关闭发送中断  

            USART1->DR =  something;        // Yes, Send character                        

        }                                             

    }    

}      


下面给一个利用环形缓冲区的串口驱动程序。


#ifndef _COM_BUFFERED_H_  

#define _COM_BUFFERED_H_  

  

#define  COM1                   0  

#define  COM2                   1  

  

#define  COM_RX_BUF_SIZE        64                /* Number of characters in Rx ring buffer             */  

#define  COM_TX_BUF_SIZE        64                /* Number of characters in Tx ring buffer             */  

  

#define  COM_NO_ERR             0                /* Function call was successful                       */  

#define  COM_BAD_CH             1                /* Invalid communications port channel                */  

#define  COM_RX_EMPTY           2                /* Rx buffer is empty, no character available         */  

#define  COM_TX_FULL            3                /* Tx buffer is full, could not deposit character     */  

#define  COM_TX_EMPTY           4                /* If the Tx buffer is empty.                         */  

  

  

/************************************************************ 

 * function : COMGetCharB  

 * parameter: char port, port can be COM1 / COM2 

 * parameter: char* err   is a pointer to where an error code will be placed: 

 *                   *err is set to COM_NO_ERR   if a character is available 

 *                   *err is set to COM_RX_EMPTY if the Rx buffer is empty 

 *                   *err is set to COM_BAD_CH   if you have specified an invalid channel 

 * return   : char 

 * usage    : This function is called by your application to obtain a character from the communications 

 *               channel. 

 * changelog:  

 *************************************************************/  

unsigned char  COMGetCharB (unsigned char ch, unsigned char *err);  

  

/************************************************************ 

 * function : COMPutCharB  

 * parameter: char port, port can be COM1 / COM2 

 * return   :    COMM_NO_ERR   if the function was successful (the buffer was not full) 

 *               COMM_TX_FULL  if the buffer was full 

 *               COMM_BAD_CH   if you have specified an incorrect channel 

 

 * usage    : This function is called by your application to send a character on the communications 

 *               channel.  The character to send is first inserted into the Tx buffer and will be sent by 

 *               the Tx ISR.  If this is the first character placed into the buffer, the Tx ISR will be 

 *               enabled.  If the Tx buffer is full, the character will not be sent (i.e. it will be lost) 

 * changelog:  

 *************************************************************/  

unsigned char COMPutCharB (unsigned char port, unsigned char c);  

  

/************************************************************ 

 * function : COMBufferInit  

 * parameter:  

 * return   :     

 * usage    : This function is called by your application to initialize the communications module.  You 

 *             must call this function before calling any other functions. 

 * changelog:  

 *************************************************************/  

void  COMBufferInit (void);  

  

/************************************************************ 

 * function : COMBufferIsEmpty  

 * parameter: char port, port can be COM1 / COM2 

 * return   : char 

 * usage    : This function is called by your application to see  

 *            if any character is available from the communications channel. 

 *            If at least one character is available, the function returns 

 *            FALSE(0) otherwise, the function returns TRUE(1). 

 * changelog:  

 *************************************************************/  

unsigned char  COMBufferIsEmpty (unsigned char port);  

  

/************************************************************ 

 * function : COMBufferIsFull  

 * parameter: char port, port can be COM1 / COM2 

 * return   : char 

 * usage    : This function is called by your application to see if any more characters can be placed 

 *             in the Tx buffer.  In other words, this function check to see if the Tx buffer is full. 

 *             If the buffer is full, the function returns TRUE otherwise, the function returns FALSE. 

 * changelog:  

 *************************************************************/  

unsigned char COMBufferIsFull (unsigned char port);  

  

#endif  


[cpp] view plain copy

/* 

 * file: com_buffered.c 

 * author: Li Yuan 

 * platform: STM32F107 

 * date: 2013-5-5 

 * version: 0.0.1 

 * description: UART Ring Buffer                             

**/  

  

#include "stm32f10x_usart.h"  

#include "com_buffered.h"  

  

#define OS_ENTER_CRITICAL()     __set_PRIMASK(1)  

#define OS_EXIT_CRITICAL()      __set_PRIMASK(0)     

      

/** 

 *  Enables Transmiter interrupt. 

**/  

static void COMEnableTxInt(unsigned char port)  

{  

    static USART_TypeDef* map[2] = {USART1, USART2};  

    USART_ITConfig(map[port], USART_IT_TXE, ENABLE);      

}  

/* 

********************************************************************************************************* 

推荐阅读

史海拾趣

问答坊 | AI 解惑

路由器与交换机的主要区别

路由器与交换机的主要区别体现在以下几个方面: (1)工作层次不同 最初的的交换机是工作在OSI/RM开放体系结构的数据链路层,也就是第二层,而路由器一开始就设计工作在OSI模型的网络层。由于交换机工作在OSI的第二层(数据链路层),所以它 ...…

查看全部问答>

1A线性消费类电子芯片方案

本帖最后由 jameswangsynnex 于 2015-3-3 20:01 编辑 1A线性锂电池充电器芯片(CN3056) 概述: CN3056是可以对单节锂离子或者锂-聚合物可充电电池进行恒流/恒压充电的充电器电路.该器件内部包括功率晶体管,应用时不需要外部的电流 检测电阻和阻 ...…

查看全部问答>

不宜学单片机的人(转载) (属于论坛:51单片机)

不宜学单片机的人容易问:我到底该学什么;   ----踏踏实实的学点基本的吧?连单片机都不知道是什么就想去学ARM?   c语言不会想搞LINUX?别老是好高骛远.   不宜学单片机的人容易问:谁有xxx源码?--(你给人家多少钱啊? ...…

查看全部问答>

ISE仿真的问题

module clk_fenp(                                 clk_in,               &n ...…

查看全部问答>

电脑通过手机联网,在保持GPRS连接的前提,怎样从GPRS模式切换到AT命令模式?

电脑通过手机联网,在保持GPRS连接的前提,怎样从GPRS模式切换到AT命令模式?…

查看全部问答>

我用的PDA带有红外,但不知道能不能用它当作串口来发送数据(485通讯)(寻找 欺世盗名来灌水 yangyzqo)

我用的PDA带有红外,但不知道能不能用它当作串口来发送数据(485通讯). 请各位大侠指点! 欺世盗名来灌水 你有msn吗? …

查看全部问答>

请问附件中的mic接口为什么左右两个声道可以接到一个音频线上?

如题: 还有什么时候应该把左右两个声道接一条音频信号,什么时候应该把两个声道分开接,多谢指教,不胜感激!…

查看全部问答>

5438 NRF905 SPI

用5438与NRF905做发送与接收数据的实验,用I/O口模拟SPI时没有问题,但将USCI设置为SPI模式时,无法通信,下面是接收数据的代码,麻烦大家给看一看 void RxPacket(unsigned char *RxBuf){         & ...…

查看全部问答>

提问+线性ccd的二值化,串口大师不显示二进制,求解

线性ccd的二值化,串口大师只显示十六进制,不显示二进制,调了好久,求大神解?…

查看全部问答>