该驱动采用中断方式,未来会加入DMA方式。中断方式采用FIFO的方式。用户程序直接用UartRead和UartWrite操作读写。
无论采用中断还是DMA,都会支持一个中断回调函数。该中断回调函数处理由用户自己定义,触发条件为——接收缓冲超时(1Byte的时间),接收缓冲过半,接收缓冲满,发送缓冲空,以应对UART在某些场合对实时性的需求。
该驱动采用中断方式,未来会加入DMA方式。中断方式采用FIFO的方式。用户程序直接用UartRead和UartWrite操作读写。
无论采用中断还是DMA,都会支持一个中断回调函数。该中断回调函数处理由用户自己定义,触发条件为——接收缓冲超时(1Byte的时间),接收缓冲过半,接收缓冲满,发送缓冲空,以应对UART在某些场合对实时性的需求。
同时为了支持多种OS环境(本人移植过UCOS和RTX两种OS),也可以裸奔,UART驱动中不会有任何和特定OS相关的操作,所以中断回调函数中可以向任务中发送信号量,消息邮箱等。同时任务在初始化UART时,可以分配一个缓冲供中断回调函数操作。比如中断回调函数向任务中发送一个消息邮箱,消息邮箱的缓冲可以建立在任务中,初始化串口的时候分配给串口驱动,当串口中断发生时直接把该缓冲区的指针发给任务,如果中断发送给任务的消息邮箱,指针位于中断函数的局部变量,当中断函数结束时,任务还没有收到消息邮箱,邮箱里面的“邮件”就变成了“空白”。
UART.h
/******************** (C) COPYRIGHT 2008 boost ********************
* File Name : usart.h
* Author : Luo Yiming
* Version : V1.1.0
* Date : 2013年3月19日
* Description : Header for usart.c module
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
/* Define to prevent recursive inclusion ------------------------------------ */
#ifndef __USART_H
#define __USART_H
#define UART_RX_IDLE 0x01 // Uart Rx Buffer is less than half when idle
#define UART_RX_OVF 0x02 // Uart Rx Buffer is more than half
#define UART_RX_FULL 0x04 // Uart Rx Buffer is full
#define UART_TX_DONE 0x08 // Uart Tx Buffer is empty
#define UART_PORT_MAX 5
#define UART_PORT_1 0
#define UART_PORT_2 1
#define UART_PORT_3 2
#define UART_PORT_4 3
#define UART_PORT_5 4
#define UART_FLOW_EN 0x80
#define UART_2STOP_EN 0x40
#define UART_EVEN_EN 0x20
#define UART_ODD_EN 0x10
typedef struct{
u16 rxSize;
u16 txSize;
u8* rxBuf;
u8* txBuf;
void (*isr)(uint8_t port,uint8_t event,void* msg);
void *msg;
USART_InitTypeDef init;
u8 rxdma;
u8 txdma;
}uart_seting_t;
/* Exported functions ------------------------------------------------------- */
extern void UartNvicSet(uint8_t port,uint8_t preprio,uint8_t subprio);
extern void USART_ISR(uint8_t port);
extern void UartSeting(uint8_t port,uart_seting_t seting);
extern uint16_t UartRead(uint8_t port,uint8_t *data,uint16_t len);
extern uint16_t UartWrite(uint8_t port,uint8_t *data,uint16_t len);
extern uint16_t UartRxCnt(uint8_t port);
extern uint16_t UartTxCnt(uint8_t port);
extern void UartSetIsrMsg(uint8_t port,void* msg);
#endif /* __USART_H */
/******************* (C) COPYRIGHT 2008 boost *****END OF FILE****/
UART.c
/******************** (C) COPYRIGHT 2008 litt ********************
* File Name : usart.c
* Author : luo yi ming
* Version : V1.1.0
* Date : 2013年3月19日
* Description : This file provides a set of functions needed to manage the
* communication between usart peripheral and RS485/HW/PLC.
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "usart.h"
/* Private typedef -----------------------------------------------------------*/
struct _uart_fifo_t{
//rx 12byte
u8* rxBuf; //4
u16 rxSize; //2
vu16 rxPush; //2
vu16 rxPop; //2
vu16 rxCnt; //2
//tx 12byte
u8* txBuf; //4
u16 txSize; //2
vu16 txPush; //2
vu16 txPop; //2
vu16 txCnt; //2
//Isr 4byte
void (*isr)(uint8_t port,uint8_t event,void* msg);
//task msg to isr
void* msg;
};//28
struct _uart_device_t{
struct _uart_fifo_t fifo;
USART_TypeDef* uart;
DMA_Channel_TypeDef* rxdma;
DMA_Channel_TypeDef* txdma;
};
typedef USART_TypeDef* pUSART_TypeDef;
typedef DMA_Channel_TypeDef* pDMA_Channel_TypeDef;
/* Private define ------------------------------------------------------------*/
//#define UART_OVF_LINE 16
//#define UART_MIN_FIFO 16
//#define UART_MAX_FIFO 2048
#define UART1_DMA_RX DMA1_Channel5
#define UART1_DMA_TX DMA1_Channel4
#define UART2_DMA_RX DMA1_Channel6
#define UART2_DMA_TX DMA1_Channel7
#define UART3_DMA_RX DMA1_Channel3
#define UART3_DMA_TX DMA1_Channel2
#define UART_REG_1 {USART1,UART1_DMA_RX,UART1_DMA_TX}
#define UART_REG_2 {USART2,UART2_DMA_RX,UART2_DMA_TX}
#define UART_REG_3 {USART3,UART3_DMA_RX,UART3_DMA_TX}
#define UART_REG_4 {UART4,NULL,NULL}
#define UART_REG_5 {UART5,NULL,NULL}
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
const pUSART_TypeDef USART_TABLE[UART_PORT_MAX] = {USART1,USART2,USART3,UART4,UART5};
const pDMA_Channel_TypeDef UART_DMA_RX_TABLE[UART_PORT_MAX] = {UART1_DMA_RX,UART2_DMA_RX,UART3_DMA_RX,NULL,NULL};
const pDMA_Channel_TypeDef UART_DMA_TX_TABLE[UART_PORT_MAX] = {UART1_DMA_TX,UART2_DMA_TX,UART3_DMA_TX,NULL,NULL};
static struct _uart_device_t UartDevice[UART_PORT_MAX];
/* Function -------------------------------------------------------------------*/
/*************************************************************************************************
* Name : _uart_isr
* Describe : 串口中断服务程序
* param : pfifo,uart
* Return : 无
* Create by : 罗一鸣 2012-12-03
* Moid by :
*************************************************************************************************/
static __inline void _uart_isr(uint8_t port,struct _uart_fifo_t *pfifo,USART_TypeDef *uart)
{
uint32_t ie,iflag;
uint8_t c,event = 0;
ie = __get_PRIMASK();
__set_PRIMASK(1);
iflag = (uart->CR1 & (USART_FLAG_TXE|USART_FLAG_TC|USART_FLAG_RXNE|USART_FLAG_IDLE) & uart->SR);
__set_PRIMASK(ie);
//IDLE IRQ
if(iflag & USART_FLAG_IDLE)
{
c = uart->DR;
if(pfifo->rxCnt <= (pfifo->rxSize>>1)) //rx buffer is not full when rx idle happen
{
event |= UART_RX_IDLE;
}
}
//RX IRQ
if(iflag & USART_FLAG_RXNE)
{
c = uart->DR;
if(pfifo->rxCnt < pfifo->rxSize)
{
pfifo->rxBuf[pfifo->rxPush] = c;
pfifo->rxPush += 1;
if(pfifo->rxPush >= pfifo->rxSize)
{
pfifo->rxPush = 0;
}
pfifo->rxCnt += 1;
if(pfifo->rxCnt == pfifo->rxSize) //rx buffer is full
{
event |= UART_RX_FULL;
}
else if(pfifo->rxCnt > (pfifo->rxSize>>1))//rx byte is more than half of rx buffer
{
event |= UART_RX_OVF;
}
}
}
//TXE IRQ
if(iflag & USART_FLAG_TXE)
{
uart->CR1 &= (uint16_t)~0x0080; //off TX
if(pfifo->txCnt)
{
c = pfifo->txBuf[pfifo->txPop];
uart->DR = c;
uart->CR1 |= (uint16_t)0x0080;
pfifo->txPop += 1;
if(pfifo->txPop >= pfifo->txSize)
{
pfifo->txPop = 0;
}
pfifo->txCnt -= 1;
if(pfifo->txCnt == 0)
{
event |= UART_TX_DONE;
}
}
}
//run isr function
if(NULL != pfifo->isr)
{
pfifo->isr(port,event,pfifo->msg);
}
}
/*************************************************************************************************
* Name : _uart_read_isr
* Describe : 串口读取函数中断模式
* param :
* Return :
* Create by :
* Moid by :
*************************************************************************************************/
static uint16_t _uart_read_isr(struct _uart_fifo_t *pfifo,USART_TypeDef *uart,uint8_t *data,uint16_t len)
{
uint32_t ie;
uint16_t n;
if(len == 0)
{
return 0;
}
for(n=0;n<len;n++)
{
if(n < pfifo->rxCnt)
{
*data++ = pfifo->rxBuf[pfifo->rxPop];
pfifo->rxPop += 1;
if(pfifo->rxPop>=pfifo->rxSize)
{
pfifo->rxPop = 0;
}
}
else
{
break;
}
}
ie = __get_PRIMASK();
__set_PRIMASK(1);
pfifo->rxCnt -= n;
__set_PRIMASK(ie);
return n;
}
/*************************************************************************************************
* Name : _uart_write_isr
* Describe : 串口写入函数中断模式
* param :
* Return :
* Create by :
* Moid by :
*************************************************************************************************/
static uint16_t _uart_write_isr(struct _uart_fifo_t *pfifo,USART_TypeDef *uart,uint8_t *data,uint16_t len)
{
uint32_t ie;
uint16_t n;
if(len == 0)
{
return 0;
}
for(n=0;n<len;n++)
{
if((pfifo->txSize-n) > pfifo->txCnt)
{
pfifo->txBuf[pfifo->txPush] = *data++;
pfifo->txPush += 1;
if(pfifo->txPush >= pfifo->txSize)
{
pfifo->txPush = 0;
}
}
else
{
break;
}
}
ie = __get_PRIMASK();
__set_PRIMASK(1);
pfifo->txCnt += n;
__set_PRIMASK(ie);
return n;
}
/*************************************************************************************************
* Name : UART_ISR
* Describe : 串口中断服务
* param :
* Return :
* Create by :
* Moid by :
*************************************************************************************************/
void USART_ISR(uint8_t port)
{
_uart_isr(port,&UartDevice[port].fif**ice[port].uart);
}
/*************************************************************************************************
* Name : UART_DMA_ISR
* Describe : 串口中断服务
* param :
* Return :
* Create by :
* Moid by :
*************************************************************************************************/
void UART_DMA_ISR(uint8_t port)
{
}
/*
__inline void UartDmaIsr(uint8_t port,struct UartFifo *pfifo,USART_TypeDef *uart)
{
}
*/
/*************************************************************************************************
* Name : UartSeting
* Describe :
* param :
* Return :
* Create by : 罗一鸣 Date: 2013-06-18
* Moid by :
*************************************************************************************************/
void UartSeting(uint8_t port,uart_seting_t seting)
{
UartDevice[port].uart = USART_TABLE[port];
UartDevice[port].rxdma = NULL;
UartDevice[port].txdma = NULL;
UartDevice[port].fifo.rxCnt = UartDevice[port].fifo.txCnt = 0;
UartDevice[port].fifo.rxPush = UartDevice[port].fifo.rxPop = 0;
UartDevice[port].fifo.txPush = UartDevice[port].fifo.txPop = 0;
UartDevice[port].fifo.rxSize = seting.rxSize;
UartDevice[port].fifo.rxBuf = seting.rxBuf;
UartDevice[port].fifo.txSize = seting.txSize;
UartDevice[port].fifo.txBuf = seting.txBuf;
UartDevice[port].fifo.isr = seting.isr;
UartDevice[port].fifo.msg = seting.msg;
if(seting.rxdma)
{
UartDevice[port].rxdma = UART_DMA_RX_TABLE[port];
}
if(seting.txdma)
{
UartDevice[port].txdma = UART_DMA_TX_TABLE[port];
}
USART_Init(UartDevice[port].uart, &seting.init);
}
/*************************************************************************************************
* Name : UartRead
* Describe :
* param :
* Return :
* Create by : 罗一鸣 Date: 2012-12-03
* Moid by :
*************************************************************************************************/
uint16_t UartRead(uint8_t port,uint8_t *data,uint16_t len)
{
if(UART_PORT_MAX <= port)
{
return 0;
}
if((NULL != UartDevice[port].rxdma))
{
return 0;
}
else
{
return _uart_read_isr(&UartDevice[port].fif**ice[port].uart,data,len);
}
}
/*************************************************************************************************
* Name : UartWrite
* Describe :
* param :
* Return :
* Create by : 罗一鸣 Date: 2012-12-03
* Moid by :
*************************************************************************************************/
uint16_t UartWrite(uint8_t port,uint8_t *data,uint16_t len)
{
if(UART_PORT_MAX <= port)
{
return 0;
}
if((NULL != UartDevice[port].txdma))
{
return 0;
}
else
{
return _uart_write_isr(&UartDevice[port].fif**ice[port].uart,data,len);
}
}
/*************************************************************************************************
* Name : UartRxCnt
* Describe :
* param :
* Return :
* Create by :
* Moid by :
*************************************************************************************************/
uint16_t UartRxCnt(uint8_t port)
{
return UartDevice[port].fifo.rxCnt;
}
/*************************************************************************************************
* Name : UartTxCnt
* Describe :
* param :
* Return :
* Create by :
* Moid by :
*************************************************************************************************/
uint16_t UartTxCnt(uint8_t port)
{
return UartDevice[port].fifo.txCnt;
}
/*************************************************************************************************
* Name : UartSetIsrMsg
* Describe : send msg to Isr
* param :
* Return :
* Create by : 罗一鸣 Date: 2013-06-18
* Moid by :
*************************************************************************************************/
void UartSetIsrMsg(uint8_t port,void* msg)
{
UartDevice[port].fifo.msg = msg;
}
/*************************************************************************************************
* Name : UartInit
* Describe :
* param :
* Return :
* Create by : 罗一鸣 Date: 2012-12-03
* Moid by :
*************************************************************************************************/
void UartInit(uint8_t port,uint8_t preprio,uint8_t subprio)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
if(UART_PORT_1 == port)
{
// config USART1 clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// Configure USART1 Tx (PA.09) as alternate function push-pull
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Configure USART1 Rx (PA.10) as input floating
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Set Interrupt Priority
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = preprio;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = subprio;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//CLI();
NVIC_Init(&NVIC_InitStructure);
//SEI();
}
else if(UART_PORT_2 == port)
{
// config USART2 clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
// Configure USART2 Tx (PA.02) as alternate function push-pull
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Configure USART2 Rx (PA.03) as input floating
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Set Interrupt Priority
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = preprio;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = subprio;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//CLI();
NVIC_Init(&NVIC_InitStructure);
//SEI();
}
else if(UART_PORT_3 == port)
{
// config USART3 clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
// Configure USART2 Tx (PB.10) as alternate function push-pull
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// Configure USART2 Rx (PB.11) as input floating
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// Set Interrupt Priority
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = preprio;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = subprio;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//CLI();
NVIC_Init(&NVIC_InitStructure);
//SEI();
}
}
/****************************************************************************
*************************** End of File *************************************
****************************************************************************/
|
|