STM32F10x 学习笔记7(USART实现串口通讯 3)

来源:互联网 发布:碳纤维地暖 知乎 编辑:程序博客网 时间:2024/05/17 00:10


在上一篇学习笔记《STM32F10x 学习笔记6(USART实现串口通讯 2)》给出了个利用环形缓冲区的串口驱动。最近研究了uCOS-II在STM32上的移植。下面再给个利用uCOS-II的信号量的串口驱动。整个驱动的基本框架和上一篇没什么区别,所以不多介绍。直接贴代码:

整个驱动包含四个文件:

uart.h

uart.c

COMMRTOS.H

COMMRTOS.c

其中前两个文件是对串口基本功能的封装。

uart.h 的代码如下:

#ifndef _UART_H_#define _UART_H_void USART1_Init(void);void USART2_Init(void);void UART_PutChar(USART_TypeDef* USARTx, uint8_t Data);void UART_PutStr (USART_TypeDef* USARTx, uint8_t *str);uint8_t UART_GetChar(USART_TypeDef* USARTx);#endif

uart.c 的代码

#include "stm32f10x.h"void USART1_Init(void){    GPIO_InitTypeDef GPIO_InitStructure;    USART_InitTypeDef USART_InitStructure;    NVIC_InitTypeDef NVIC_InitStructure;    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);    /* Configure USART Tx as alternate function push-pull */    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_Init(GPIOA, &GPIO_InitStructure);    /* Configure USART Rx as input floating */    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;    GPIO_Init(GPIOA, &GPIO_InitStructure);    USART_InitStructure.USART_BaudRate = 9600;    USART_InitStructure.USART_WordLength = USART_WordLength_8b;    USART_InitStructure.USART_StopBits = USART_StopBits_1;    USART_InitStructure.USART_Parity = USART_Parity_No;    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    USART_Init(USART1, &USART_InitStructure);    USART_Cmd(USART1, ENABLE);    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);}void USART2_Init(void){    GPIO_InitTypeDef GPIO_InitStructure;    USART_InitTypeDef USART_InitStructure;    NVIC_InitTypeDef NVIC_InitStructure;    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);    /* Configure USART Tx as alternate function push-pull */    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_Init(GPIOD, &GPIO_InitStructure);    /* Configure USART Rx as input floating */    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;    GPIO_Init(GPIOD, &GPIO_InitStructure);    GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);    USART_InitStructure.USART_BaudRate = 9600;    USART_InitStructure.USART_WordLength = USART_WordLength_8b;    USART_InitStructure.USART_StopBits = USART_StopBits_1;    USART_InitStructure.USART_Parity = USART_Parity_No;    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;    USART_Init(USART2, &USART_InitStructure);    USART_Cmd(USART2, ENABLE);    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    NVIC_Init(&NVIC_InitStructure);}void UART_PutChar(USART_TypeDef* USARTx, uint8_t Data){    //while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET ) {};    while((USARTx->SR & USART_FLAG_TXE) == 0x00) {};    //USART_SendData (USARTx, Data);    USARTx->DR = Data;}void UART_PutStr(USART_TypeDef* USARTx, uint8_t *str){    while(0 != *str)    {        UART_PutChar(USARTx, *str);        str++;    }}uint8_t UART_GetChar(USART_TypeDef* USARTx){    //while( USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) == RESET) {};    while((USARTx->SR & USART_FLAG_RXNE) == 0x00) {};    //return USART_ReceiveData(USARTx);    return (USARTx->DR & 0xff);}

commrtos.h 的代码如下:

#ifndef _COMMRTOS_H_#define _COMMRTOS_H_#ifndef  CFG_H#define  COMM_RX_BUF_SIZE      64                /* Number of characters in Rx ring buffer             */#define  COMM_TX_BUF_SIZE      64                /* Number of characters in Tx ring buffer             */#endif/***********************************************************************************************************                                               CONSTANTS**********************************************************************************************************/#ifndef  FALSE#define  FALSE                0x00#endif#ifndef  TRUE#define  TRUE                 0xff#endif#ifndef  NUL#define  NUL                  0x00#endif#define  COM1                  0#define  COM2                  1/* ERROR CODES */#define  COMM_NO_ERR           0                /* Function call was successful                       */#define  COMM_BAD_CH           1                /* Invalid communications port channel                */#define  COMM_RX_EMPTY         2                /* Rx buffer is empty, no character available         */#define  COMM_TX_FULL          3                /* Tx buffer is full, could not deposit character     */#define  COMM_TX_EMPTY         4                /* If the Tx buffer is empty.                         */#define  COMM_RX_TIMEOUT       5                /* If a timeout occurred while waiting for a character*/#define  COMM_TX_TIMEOUT       6                /* If a timeout occurred while waiting to send a char.*/#define  COMM_PARITY_NONE      0                /* Defines for setting parity                         */#define  COMM_PARITY_ODD       1#define  COMM_PARITY_EVEN      2unsigned char CommGetChar(unsigned char ch, unsigned short to, unsigned char *err);void COMInit(void);unsigned char CommIsEmpty(unsigned char ch);unsigned char CommIsFull(unsigned char ch);unsigned char CommPutChar(unsigned char ch, unsigned char c, unsigned short to);void CommPutStr(unsigned char ch, uint8_t *str);#endif

commrtos.c 的代码如下:

#include "stm32f10x_usart.h"#include "includes.h"#include "COMMRTOS.H"/* * DATA TYPES */typedef struct {    unsigned short     RingBufRxCtr;                /* Number of characters in the Rx ring buffer              */    OS_EVENT  *RingBufRxSem;                /* Pointer to Rx semaphore                                 */    unsigned char     *RingBufRxInPtr;              /* Pointer to where next character will be inserted        */    unsigned char     *RingBufRxOutPtr;             /* Pointer from where next character will be extracted     */    unsigned char      RingBufRx[COMM_RX_BUF_SIZE]; /* Ring buffer character storage (Rx)                      */    unsigned short     RingBufTxCtr;                /* Number of characters in the Tx ring buffer              */    OS_EVENT  *RingBufTxSem;                /* Pointer to Tx semaphore                                 */    unsigned char     *RingBufTxInPtr;              /* Pointer to where next character will be inserted        */    unsigned char     *RingBufTxOutPtr;             /* Pointer from where next character will be extracted     */    unsigned char      RingBufTx[COMM_TX_BUF_SIZE]; /* Ring buffer character storage (Tx)                      */} COMM_RING_BUF;/* * GLOBAL VARIABLES */COMM_RING_BUF  Comm1Buf;COMM_RING_BUF  Comm2Buf;static void COMEnableTxInt(unsigned char port){    static USART_TypeDef* map[2] = {USART1, USART2};    //USART_ITConfig(map[port], USART_IT_TXE, ENABLE);    map[port]->CR1 |= USART_FLAG_TXE;}/***********************************************************************************************************                                    REMOVE CHARACTER FROM RING BUFFER*** Description : This function is called by your application to obtain a character from the communications*               channel.  The function will wait for a character to be received on the serial channel or*               until the function times out.* Arguments   : 'ch'    is the COMM port channel number and can either be:*                           COMM1*                           COMM2*               'to'    is the amount of time (in clock ticks) that the calling function is willing to*                       wait for a character to arrive.  If you specify a timeout of 0, the function will*                       wait forever for a character to arrive.*               'err'   is a pointer to where an error code will be placed:*                           *err is set to COMM_NO_ERR     if a character has been received*                           *err is set to COMM_RX_TIMEOUT if a timeout occurred*                           *err is set to COMM_BAD_CH     if you specify an invalid channel number* Returns     : The character in the buffer (or NUL if a timeout occurred)**********************************************************************************************************/unsigned char  CommGetChar(unsigned char ch, unsigned short to, unsigned char *err){    unsigned char c;    unsigned char oserr;    COMM_RING_BUF *pbuf;    OS_CPU_SR  cpu_sr;    switch(ch)    {   /* Obtain pointer to communications channel */    case COM1:        pbuf = &Comm1Buf;        break;    case COM2:        pbuf = &Comm2Buf;        break;    default:        *err = COMM_BAD_CH;        return (NUL);    }    OSSemPend(pbuf->RingBufRxSem, to, &oserr);             /* Wait for character to arrive             */    if(oserr == OS_TIMEOUT)    {   /* See if characters received within timeout*/        *err = COMM_RX_TIMEOUT;                            /* No, return error code                    */        return (NUL);    }    else    {        OS_ENTER_CRITICAL();        pbuf->RingBufRxCtr--;                              /* Yes, decrement character count           */        c = *pbuf->RingBufRxOutPtr++;                      /* Get character from buffer                */        if(pbuf->RingBufRxOutPtr == &pbuf->RingBufRx[COMM_RX_BUF_SIZE])        {   /* Wrap OUT pointer     */            pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];        }        OS_EXIT_CRITICAL();        *err = COMM_NO_ERR;        return (c);    }}void CommPutStr(unsigned char ch, uint8_t *str){    while(0 != *str)    {        CommPutChar(ch, *str, 0);        str++;    }}static unsigned char  COMGetTxChar(unsigned char ch, unsigned char *err){    unsigned char c;    COMM_RING_BUF *pbuf;    switch(ch)    {   /* Obtain pointer to communications channel */    case COM1:        pbuf = &Comm1Buf;        break;    case COM2:        pbuf = &Comm2Buf;        break;    default:        *err = COMM_BAD_CH;        return (NUL);    }    if(pbuf->RingBufTxCtr > 0)    {   /* See if buffer is empty                   */        pbuf->RingBufTxCtr--;                              /* No, decrement character count            */        c = *pbuf->RingBufTxOutPtr++;                      /* Get character from buffer                */        if(pbuf->RingBufTxOutPtr == &pbuf->RingBufTx[COMM_TX_BUF_SIZE])        {   /* Wrap OUT pointer     */            pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];        }        OSSemPost(pbuf->RingBufTxSem);                     /* Indicate that character will be sent     */        *err = COMM_NO_ERR;        return (c);                                        /* Characters are still available           */    }    else    {        *err = COMM_TX_EMPTY;        return (NUL);                                      /* Buffer is empty                          */    }}/***********************************************************************************************************                                  INITIALIZE COMMUNICATIONS MODULE* Description : This function is called by your application to initialize the communications module.  You*               must call this function before calling any other functions.* Arguments   : none**********************************************************************************************************/void  COMInit(void){    COMM_RING_BUF *pbuf;    pbuf                  = &Comm1Buf;                     /* Initialize the ring buffer for COMM1     */    pbuf->RingBufRxCtr    = 0;    pbuf->RingBufRxInPtr  = &pbuf->RingBufRx[0];    pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];    pbuf->RingBufRxSem    = OSSemCreate(0);    pbuf->RingBufTxCtr    = 0;    pbuf->RingBufTxInPtr  = &pbuf->RingBufTx[0];    pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];    pbuf->RingBufTxSem    = OSSemCreate(COMM_TX_BUF_SIZE);    pbuf                  = &Comm2Buf;                     /* Initialize the ring buffer for COMM2     */    pbuf->RingBufRxCtr    = 0;    pbuf->RingBufRxInPtr  = &pbuf->RingBufRx[0];    pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];    pbuf->RingBufRxSem    = OSSemCreate(0);    pbuf->RingBufTxCtr    = 0;    pbuf->RingBufTxInPtr  = &pbuf->RingBufTx[0];    pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];    pbuf->RingBufTxSem    = OSSemCreate(COMM_TX_BUF_SIZE);}/***********************************************************************************************************                                   SEE IF RX CHARACTER BUFFER IS EMPTY*** Description : 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 otherwise, the function returns TRUE.* Arguments   : 'ch'    is the COMM port channel number and can either be:*                           COMM1*                           COMM2* Returns     : TRUE    if the buffer IS empty.*               FALSE   if the buffer IS NOT empty or you have specified an incorrect channel.**********************************************************************************************************/unsigned char CommIsEmpty(unsigned char ch){    unsigned char empty;    COMM_RING_BUF *pbuf;    OS_CPU_SR  cpu_sr;    switch(ch)    {   /* Obtain pointer to communications channel */    case COM1:        pbuf = &Comm1Buf;        break;    case COM2:        pbuf = &Comm2Buf;        break;    default:        return (TRUE);    }    OS_ENTER_CRITICAL();    if(pbuf->RingBufRxCtr > 0)    {   /* See if buffer is empty                   */        empty = FALSE;                                     /* Buffer is NOT empty                      */    }    else    {        empty = TRUE;                                      /* Buffer is empty                          */    }    OS_EXIT_CRITICAL();    return (empty);}/***********************************************************************************************************                                   SEE IF TX CHARACTER BUFFER IS FULL* Description : 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.* Arguments   : 'ch'    is the COMM port channel number and can either be:*                           COMM1*                           COMM2* Returns     : TRUE    if the buffer IS full.*               FALSE   if the buffer IS NOT full or you have specified an incorrect channel.**********************************************************************************************************/unsigned char CommIsFull(unsigned char ch){    unsigned char        full;    COMM_RING_BUF *pbuf;    OS_CPU_SR  cpu_sr;    switch(ch)    {   /* Obtain pointer to communications channel */    case COM1:        pbuf = &Comm1Buf;        break;    case COM2:        pbuf = &Comm2Buf;        break;    default:        return (TRUE);    }    OS_ENTER_CRITICAL();    if(pbuf->RingBufTxCtr < COMM_TX_BUF_SIZE)    {   /* See if buffer is full                    */        full = FALSE;                                      /* Buffer is NOT full                       */    }    else    {        full = TRUE;                                       /* Buffer is full                           */    }    OS_EXIT_CRITICAL();    return (full);}/***********************************************************************************************************                                            OUTPUT CHARACTER*** Description : This function is called by your application to send a character on the communications*               channel.  The function will wait for the buffer to empty out if the buffer is full.*               The function returns to your application if the buffer doesn't empty within the specified*               timeout.  A timeout value of 0 means that the calling function will wait forever for the*               buffer to empty out.  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.* Arguments   : 'ch'    is the COMM port channel number and can either be:*                           COMM1*                           COMM2*               'c'     is the character to send.*               'to'    is the timeout (in clock ticks) to wait in case the buffer is full.  If you*                       specify a timeout of 0, the function will wait forever for the buffer to empty.* Returns     : COMM_NO_ERR      if the character was placed in the Tx buffer*               COMM_TX_TIMEOUT  if the buffer didn't empty within the specified timeout period*               COMM_BAD_CH      if you specify an invalid channel number**********************************************************************************************************/unsigned char CommPutChar(unsigned char ch, unsigned char c, unsigned short to){    unsigned char oserr;    COMM_RING_BUF *pbuf;    OS_CPU_SR cpu_sr;    switch(ch)    {   /* Obtain pointer to communications channel */    case COM1:        pbuf = &Comm1Buf;        break;    case COM2:        pbuf = &Comm2Buf;        break;    default:        return (COMM_BAD_CH);    }    OSSemPend(pbuf->RingBufTxSem, to, &oserr);             /* Wait for space in Tx buffer              */    if(oserr == OS_TIMEOUT)    {        return (COMM_TX_TIMEOUT);                          /* Timed out, return error code             */    }    OS_ENTER_CRITICAL();    pbuf->RingBufTxCtr++;                                  /* No, increment character count            */    *pbuf->RingBufTxInPtr++ = c;                           /* Put character into buffer                */    if(pbuf->RingBufTxInPtr == &pbuf->RingBufTx[COMM_TX_BUF_SIZE])    {   /* Wrap IN pointer           */        pbuf->RingBufTxInPtr = &pbuf->RingBufTx[0];    }    if(pbuf->RingBufTxCtr == 1)    {   /* See if this is the first character       */        COMEnableTxInt(ch);                                /* Yes, Enable Tx interrupts                */    }    OS_EXIT_CRITICAL();    return (COMM_NO_ERR);}/***********************************************************************************************************                                    INSERT CHARACTER INTO RING BUFFER*** Description : This function is called by the Rx ISR to insert a character into the receive ring buffer.* Arguments   : 'ch'    is the COMM port channel number and can either be:*                           COMM1*                           COMM2*               'c'     is the character to insert into the ring buffer.  If the buffer is full, the*                       character will not be inserted, it will be lost.**********************************************************************************************************/static void COMPutRxChar(unsigned char ch, unsigned char c){    COMM_RING_BUF *pbuf;    switch(ch)    {   /* Obtain pointer to communications channel */    case COM1:        pbuf = &Comm1Buf;        break;    case COM2:        pbuf = &Comm2Buf;        break;    default:        return;    }    if(pbuf->RingBufRxCtr < COMM_RX_BUF_SIZE)    {   /* See if buffer is full                    */        pbuf->RingBufRxCtr++;                              /* No, increment character count            */        *pbuf->RingBufRxInPtr++ = c;                       /* Put character into buffer                */        if(pbuf->RingBufRxInPtr == &pbuf->RingBufRx[COMM_RX_BUF_SIZE])        {   /* Wrap IN pointer           */            pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0];        }        OSSemPost(pbuf->RingBufRxSem);                     /* Indicate that character was received     */    }}// This function is called by the Rx ISR to insert a character into the receive ring buffer.void USART1_IRQHandler(void){    unsigned int data;    unsigned char err;    OS_CPU_SR  cpu_sr;    OS_ENTER_CRITICAL();        /* Tell uC/OS-II that we are starting an ISR  */    OSIntNesting++;    OS_EXIT_CRITICAL();    if(USART1->SR & 0x0F)    {        // See if we have some kind of error        // Clear interrupt (do nothing about it!)        data = USART1->DR;    }    else if(USART1->SR & USART_FLAG_RXNE) //Receive Data Reg Full Flag    {        data = USART1->DR;        COMPutRxChar(COM1, data);                    // Insert received character into buffer    }    else if(USART1->SR & USART_FLAG_TXE)    {        data = COMGetTxChar(COM1, &err);             // Get next character to send.        if(err == COMM_TX_EMPTY)        {   // Do we have anymore characters to send ?            // No,  Disable Tx interrupts            //USART_ITConfig(USART1, USART_IT_TXE| USART_IT_TC, DISABLE);            USART1->CR1 &= ~USART_FLAG_TXE | USART_FLAG_TC;        }        else        {            USART1->DR = data;        // Yes, Send character        }    }    OSIntExit();}void USART2_IRQHandler(void){    unsigned int data;    unsigned char err;    OS_CPU_SR  cpu_sr;    OS_ENTER_CRITICAL();        /* Tell uC/OS-II that we are starting an ISR  */    OSIntNesting++;    OS_EXIT_CRITICAL();    if(USART2->SR & 0x0F)    {        // See if we have some kind of error        // Clear interrupt (do nothing about it!)        data = USART2->DR;    }    else if(USART2->SR & USART_FLAG_RXNE) //Receive Data Reg Full Flag    {        data = USART2->DR;        COMPutRxChar(COM2, data);                    // Insert received character into buffer    }    else if(USART2->SR & USART_FLAG_TXE)    {        data = COMGetTxChar(COM2, &err);             // Get next character to send.        if(err == COMM_TX_EMPTY)        {   // Do we have anymore characters to send ?            // No,  Disable Tx interrupts            //USART_ITConfig(USART2, USART_IT_TXE| USART_IT_TC, DISABLE);            USART2->CR1 &= ~USART_FLAG_TXE | USART_FLAG_TC;        }        else        {            USART2->DR = data;        // Yes, Send character        }    }    OSIntExit();}


下面再给出个测试代码:

#include "stm32f10x.h"#include "uart.h"#include "led.h"#include "COMMRTOS.H"#include "ucos_ii.h"#define  TASK_STK_SIZE 128OS_STK TaskStartStk[TASK_STK_SIZE];OS_STK TaskUartReadStk[TASK_STK_SIZE];void TaskUartRead(void *pdata){unsigned char err;unsigned char c;for(;;){c = CommGetChar(COM2, 0, &err);if(err == COMM_NO_ERR)CommPutChar(COM2, c, 0);}}void TaskStart(void *pdata){SysTick_Config(SystemCoreClock/10);USART1_Init();USART2_Init();COMInit();//USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);USART1->CR1 |= USART_FLAG_RXNE;USART2->CR1 |= USART_FLAG_RXNE;OSTaskCreate(TaskUartRead, (void *)0, &(TaskUartReadStk[TASK_STK_SIZE-1]), 2);UART_PutStr (USART2, "USART2 Hello World!\n\r");//CommPutChar(COM2, '+', 0);CommPutStr(COM2, "CommPutCharB\n\r");for(;;){LED_Spark();CommPutChar(COM2, '+', 0);OSTimeDly(10);}}int main(void){SystemInit();LED_Init();OSInit();OSTaskCreate(TaskStart, (void *)0, &(TaskStartStk[TASK_STK_SIZE-1]), 1);OSStart();for(;;){}}