因项目需要使用3个UART, 但该系列只有2个UART.
只好模拟一个出来使用。
所以,本篇文章,通过使用两个GPIO 口,加 一个定时器, 来达到 模拟串口的 功能。
代码仅供参考:
1. IO_USART.h
#include "gd32e23x.h"#define Number_Of_softUarts 1
#define SoftUartTxBufferSize 32
#define SoftUartRxBufferSize 64
#define SoftUart_DATA_LEN 8 // Max 8 Bit//ADD
#ifndef SoftUartID
#define SoftUartID 0
#endif#define SOFTUART_COUNTER_PERIOD 20
//endtypedef enum {SoftUart_OK,SoftUart_Error
}SoftUartState_E;typedef struct{uint8_t Tx[SoftUartTxBufferSize];uint8_t Rx[SoftUartTxBufferSize];
}SoftUartBuffer_S;typedef struct{__IO uint8_t TxNComplated;uint8_t TxEnable;uint8_t RxEnable;uint8_t TxBitShift,TxBitCounter;uint8_t RxBitShift,RxBitCounter;uint8_t TxIndex,TxSize;uint8_t RxIndex;SoftUartBuffer_S *Buffer;uint32_t TxPort;uint16_t TxPin;uint32_t RxPort;uint16_t RxPin;uint8_t RxTimingFlag;uint8_t RxBitOffset;
}SoftUart_S;void SoftUartHandler(void);
void SoftUartWaitUntilTxComplete(uint8_t SoftUartNumber);
uint8_t SoftUartRxAlavailable(uint8_t SoftUartNumber);
SoftUartState_E SoftUartPuts(uint8_t SoftUartNumber,uint8_t *Str,uint8_t Len);
SoftUartState_E SoftUartEnableRx(uint8_t SoftUartNumber);
SoftUartState_E SoftUartDisableRx(uint8_t SoftUartNumber);
SoftUartState_E SoftUartInit(uint8_t SoftUartNumber,uint32_t TxPort,uint16_t TxPin,uint32_t RxPort,uint16_t RxPin);
SoftUartState_E SoftUartReadRxBuffer(uint8_t SoftUartNumber,uint8_t* Buffer,uint8_t Len);void SoftUart_GPIO_Config(uint32_t TxPort,uint16_t TxPin,uint32_t RxPort,uint16_t RxPin);
void SoftUartTimerConfig(uint32_t timer_n,rcu_periph_enum periph,uint32_t periods);
2. IO_USART.c
#include "IO_USART.h"/**/// Some internal define
#define SoftUart_DATA_LEN_C1 (SoftUart_DATA_LEN+1)
#define SoftUart_DATA_LEN_C2 (SoftUart_DATA_LEN+2)SoftUart_S SUart[Number_Of_softUarts];
// TX RX Data Buffer
SoftUartBuffer_S SUBuffer[Number_Of_softUarts];
// For timing division
__IO uint8_t SU_Timer=0;static FlagStatus SoftUartGpioReadPin(uint32_t gpio_periph, uint32_t pin){return gpio_input_bit_get(gpio_periph,pin);
}// Write TX single Pin Value
static void SoftUartGpioWritePin(uint32_t gpio_periph, uint32_t pin,FlagStatus Pinstate){gpio_bit_write(gpio_periph,pin,Pinstate);
}// Initial Soft Uart
SoftUartState_E SoftUartInit(uint8_t SoftUartNumber,uint32_t TxPort,uint16_t TxPin,uint32_t RxPort,uint16_t RxPin)
{if(SoftUartNumber>=Number_Of_softUarts)return SoftUart_Error;//ADDSoftUart_GPIO_Config(TxPort,TxPin,RxPort,RxPin);SUart[SoftUartNumber].TxNComplated=0;SUart[SoftUartNumber].RxBitCounter=0;SUart[SoftUartNumber].RxBitShift=0;SUart[SoftUartNumber].RxIndex=0;SUart[SoftUartNumber].TxEnable=0;SUart[SoftUartNumber].RxEnable=0;SUart[SoftUartNumber].TxBitCounter=0;SUart[SoftUartNumber].TxBitShift=0;SUart[SoftUartNumber].TxIndex=0;SUart[SoftUartNumber].TxSize=0;SUart[SoftUartNumber].Buffer=&SUBuffer[SoftUartNumber];SUart[SoftUartNumber].RxPort=RxPort;SUart[SoftUartNumber].RxPin=RxPin;SUart[SoftUartNumber].TxPort=TxPort;SUart[SoftUartNumber].TxPin=TxPin;SUart[SoftUartNumber].RxTimingFlag=0;SUart[SoftUartNumber].RxBitOffset=0;return SoftUart_OK;
}static void SoftUartTransmitBit(SoftUart_S *SU,uint8_t Bit0_1){SoftUartGpioWritePin(SU->TxPort,SU->TxPin,(FlagStatus)Bit0_1);
}SoftUartState_E SoftUartEnableRx(uint8_t SoftUartNumber){if(SoftUartNumber >= Number_Of_softUarts)return SoftUart_Error;SUart[SoftUartNumber].RxEnable = 1;return SoftUart_OK;
}SoftUartState_E SoftUartDisableRx(uint8_t SoftUartNumber){if(SoftUartNumber >= Number_Of_softUarts)return SoftUart_Error;SUart[SoftUartNumber].RxEnable = 0;return SoftUart_OK;
}uint8_t SoftUartRxAlavailable(uint8_t SoftUartNumber){return SUart[SoftUartNumber].RxIndex;
}SoftUartState_E SoftUartReadRxBuffer(uint8_t SoftUartNumber,uint8_t* Buffer,uint8_t Len){int i;if(SoftUartNumber >= Number_Of_softUarts)return SoftUart_Error;for ( i = 0; i < Len; i++){/* code */Buffer[i] = SUart[SoftUartNumber].Buffer->Rx[i];}for ( i = 0; i < SUart[SoftUartNumber].RxIndex; i++){/* code */SUart[SoftUartNumber].Buffer->Rx[i] = SUart[SoftUartNumber].Buffer->Rx[i+Len]; }SUart[SoftUartNumber].RxIndex -=Len;return SoftUart_OK;}// Soft Uart Transmit Data Process
static void SoftUartTxProcess(SoftUart_S *SU)
{if(SU->TxEnable){// Startif(SU->TxBitCounter==0){SU->TxNComplated=1;SU->TxBitShift=0;SoftUartTransmitBit(SU,0);SU->TxBitCounter++;}// Dataelse if(SU->TxBitCounter<SoftUart_DATA_LEN_C1){SoftUartTransmitBit(SU,((SU->Buffer->Tx[SU->TxIndex])>>(SU->TxBitShift))&0x01);SU->TxBitCounter++;SU->TxBitShift++;}// Stopelse if(SU->TxBitCounter==SoftUart_DATA_LEN_C1){SoftUartTransmitBit(SU,1);SU->TxBitCounter++;}//Completeelse if(SU->TxBitCounter==SoftUart_DATA_LEN_C2){// Reset Bit CounterSU->TxBitCounter=0;// Ready To Send Another DataSU->TxIndex++;// Check Size of Dataif(SU->TxSize > SU->TxIndex){// Continue SendingSU->TxNComplated=1;SU->TxEnable=1;}else{// FinishSU->TxNComplated=0;SU->TxEnable=0;//printf(" Send Finish\r\n");}}}
}// Soft Uart Receive Data Process
static void SoftUartRxDataBitProcess(SoftUart_S *SU,uint8_t B0_1)
{if(SU->RxEnable){// Startif(SU->RxBitCounter==0){// Start Bit is 0if(B0_1)return;SU->RxBitShift=0;SU->RxBitCounter++;SU->Buffer->Rx[SU->RxIndex]=0;}// Dataelse if(SU->RxBitCounter<SoftUart_DATA_LEN_C1){SU->Buffer->Rx[SU->RxIndex]|=((B0_1&0x01)<<SU->RxBitShift);SU->RxBitCounter++;SU->RxBitShift++;}// Stop and Completeelse if(SU->RxBitCounter==SoftUart_DATA_LEN_C1){SU->RxBitCounter=0;SU->RxTimingFlag=0;//Stop Bit must be 1if(B0_1){// Received successfully// Change RX Buffer Indexif((SU->RxIndex)<(SoftUartRxBufferSize-1))(SU->RxIndex)++;}// if not : ERROR -> Overwrite data}}
}// Wait Until Transmit Completed
// You do not usually need to use this function!
void SoftUartWaitUntilTxComplete(uint8_t SoftUartNumber)
{while(SUart[SoftUartNumber].TxNComplated);
}// Copy Data to Transmit Buffer and Start Sending
SoftUartState_E SoftUartPuts(uint8_t SoftUartNumber,uint8_t *Str,uint8_t Len)
{int i;if(SoftUartNumber>=Number_Of_softUarts)return SoftUart_Error;if(SUart[SoftUartNumber].TxNComplated) return SoftUart_Error;SUart[SoftUartNumber].TxIndex=0;SUart[SoftUartNumber].TxSize=Len;for(i=0;i<Len;i++){SUart[SoftUartNumber].Buffer->Tx[i]= Str[i];}SUart[SoftUartNumber].TxNComplated=1;SUart[SoftUartNumber].TxEnable=1;//printf("SoftUartPuts OK ok \r\n");return SoftUart_OK;
}// Capture RX and Get BitOffset
static uint8_t SoftUartScanRxPorts(void)
{int i;uint8_t Buffer=0x00,Bit;for(i=0;i<Number_Of_softUarts;i++){// Read RX GPIO ValueBit=SoftUartGpioReadPin(SUart[i].RxPort,SUart[i].RxPin);// Starting conditionsif(!SUart[i].RxBitCounter && !SUart[i].RxTimingFlag && !Bit){// Save RX Bit Offset// Calculate middle position of data pulsSUart[i].RxBitOffset=((SU_Timer+2)%5);// Timing Offset is SetSUart[i].RxTimingFlag=1;}// Add all RX GPIO State to BufferBuffer|=((Bit&0x01)<<i);}return Buffer;
}// SoftUartHandler must call in interrupt every 0.2*(1/BR)
// if BR=9600 then 0.2*(1/9600)=20.8333333 uS
void SoftUartHandler(void){int i;uint8_t SU_DBuffer;// Capture RX and Get BitOffsetSU_DBuffer = SoftUartScanRxPorts();for(i=0;i < Number_Of_softUarts;i++){// Receive Data if we in middle data pulse positionif(SUart[i].RxBitOffset == SU_Timer){SoftUartRxDataBitProcess(&SUart[i],((SU_DBuffer>>i)&0x01));}}// Sending always happens in the first time slotif(SU_Timer==0){// Transmit Datafor(i=0;i < Number_Of_softUarts;i++){SoftUartTxProcess(&SUart[i]);}}// Timing processSU_Timer++;if(SU_Timer >= 5){SU_Timer=0;}
}void SoftUart_GPIO_Config(uint32_t TxPort,uint16_t TxPin,uint32_t RxPort,uint16_t RxPin){gpio_mode_set(TxPort, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, TxPin);gpio_output_options_set(TxPort, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, TxPin);gpio_mode_set(RxPort, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, RxPin);gpio_output_options_set(RxPort, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RxPin);
}void SoftUartTimerConfig(uint32_t timer_n,rcu_periph_enum periph,uint32_t periods){timer_oc_parameter_struct timer_ocinitpara;timer_parameter_struct timer_initpara;/* enable the peripherals clock */rcu_periph_clock_enable(periph);/* deinit a TIMER */timer_deinit(timer_n);/* initialize TIMER init parameter struct */timer_struct_para_init(&timer_initpara);/* TIMER2 configuration */timer_initpara.prescaler = 74;timer_initpara.alignedmode = TIMER_COUNTER_EDGE;timer_initpara.counterdirection = TIMER_COUNTER_UP;timer_initpara.period = (periods-1);timer_initpara.clockdivision = TIMER_CKDIV_DIV1;timer_init(timer_n, &timer_initpara);/* clear channel 0 interrupt bit */timer_interrupt_flag_clear(timer_n, TIMER_INT_FLAG_UP);/* enable the TIMER interrupt */timer_interrupt_enable(timer_n, TIMER_INT_UP);/* enable a TIMER */timer_enable(timer_n);//add ...nvic_irq_enable(TIMER16_IRQn, 0);
}void TIMER16_IRQHandler(void){if(SET == timer_interrupt_flag_get(TIMER16, TIMER_INT_FLAG_UP)){/* clear channel 0 interrupt bit */timer_interrupt_flag_clear(TIMER16, TIMER_INT_FLAG_UP);SoftUartHandler();}
}//for example:
//1. init timer::
// SoftUartTimerConfig(TIMER16,RCU_TIMER16,20);
//2. next :
// SoftUartInit(0,GPIOA,GPIO_PIN_5,GPIOA,GPIO_PIN_6);
//:
3. main.c
#include "IO_USART.h"int main()
{uint8_t SoftUartRx;uint8_t i= 0;uint8_t mm_Rx[SoftUartTxBufferSize]={0};systick_config();gd_eval_com_init(EVAL_COM);SoftUartInit(SoftUartID,GPIOA,GPIO_PIN_5,GPIOA,GPIO_PIN_6);//A5->Tx A6->RxSoftUartTimerConfig(TIMER16,RCU_TIMER16,SOFTUART_COUNTER_PERIOD);SoftUartEnableRx(SoftUartID);//使能接收while (1){delay_1ms(500);delay_1ms(500);SoftUartRx = SoftUartRxAlavailable(SoftUartID);if(SoftUartRx > 0){memset(mm_Rx,0,SoftUartTxBufferSize);SoftUartReadRxBuffer(SoftUartID,mm_Rx,SoftUartRx);for(i=0;i<SoftUartRx;i++){printf("Rx,i:%d__ 0x%x, \r\n",i,mm_Rx[i]);}SoftUartPuts(SoftUartID,mm_Rx,SoftUartRx);}}return 0;
}
STM32 见github地址:
STM32 模拟串口 的使用 - github地址