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(;;){}}
- STM32F10x 学习笔记7(USART实现串口通讯 3)
- STM32F10x 学习笔记5(USART实现串口通讯 1)
- STM32F10x 学习笔记6(USART实现串口通讯 2)
- STM32F10x 学习笔记之USART实现串口通讯
- STM32F10x 学习笔记之USART实现串口通讯 DMA 方式
- STM32F10x 学习笔记8(USART实现串口通讯 DMA 方式)
- STM32F10x USART串口映射功能实现串口通讯 485初始化
- STM32学习笔记(7):USART串口的使用
- STM32学习笔记(7):USART串口的使用
- STM32学习笔记(7):USART串口的使用
- STM32学习笔记(7):USART串口的使用
- 【PIC32MZ】Usart串口通讯
- STM32串口USART通讯
- STM32串口USART通讯
- 20130408-[转]STM32学习笔记(7):USART串口的使用
- STM32学习笔记:USART串口的…
- 串口通讯学习笔记
- STM32F10x 学习笔记 1 (使用STM32F10x StdPeriph Driver)
- 环形缓冲区的实现原理(ring buffer)
- appendix C
- Linux下编写C++实例程序(二)
- 40+精彩的HTML5实例和教程
- java静态块和构造器执行时间的区别
- STM32F10x 学习笔记7(USART实现串口通讯 3)
- 在android模拟器运行arm 移植的 c程序
- eclipse打开java文件,注释内容为乱码
- mysql 中最常用的sql语句
- ORA-00313的解决
- <<微软:DirectShow开发指南》第11章 Using the Sample Grabber Filter
- java.lang.NoClassDefFoundError: com/opensymphony/xwork2/config/FileManagerProvider
- MyEclipse不编译解决
- ImageView的使用