UART1_TX GPIO_PA02
UART1_RX GPIO_PA03
int32_t main(void)
{
Uart1_Config(); //usrt1功能配置
Uart1_PortInit(); //usrt1引脚配置
}
static void Uart1_Config(void)
{
stc_uart_cfg_t stcCfg;
DDL_ZERO_STRUCT(stcCfg);
///< 开启外设时钟
Sysctrl_SetPeripheralGate(SysctrlPeripheralUart1,TRUE);///<使能uart1模块时钟
///<UART Init
stcCfg.enRunMode = UartMskMode1; ///<模式1
stcCfg.enStopBit = UartMsk1bit; ///<1bit停止位
stcCfg.enMmdorCk = UartMskEven; ///<偶检验
stcCfg.stcBaud.u32Baud = 9600; ///<波特率9600
stcCfg.stcBaud.enClkDiv = UartMsk8Or16Div; ///<通道采样分频配置
stcCfg.stcBaud.u32Pclk = Sysctrl_GetPClkFreq(); ///<获得外设时钟(PCLK)频率值
Uart_Init(M0P_UART1, &stcCfg); ///<串口初始化
///<UART中断使能
Uart_ClrStatus(M0P_UART1,UartRC); ///<清接收请求
Uart_ClrStatus(M0P_UART1,UartTC); ///<清接收请求
Uart_EnableIrq(M0P_UART1,UartRxIrq); ///<使能串口接收中断
Uart_DisableIrq(M0P_UART1,UartTxIrq); ///<关闭串口发送中断
EnableNvic(UART1_3_IRQn, IrqLevel3, TRUE); ///<系统中断使能
}
static void Uart1_PortInit(void)
{
stc_gpio_cfg_t stcGpioCfg;
DDL_ZERO_STRUCT(stcGpioCfg);
Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE); //使能GPIO模块时钟
///<TX
stcGpioCfg.enDir = GpioDirOut; //端口方向配置 输出
stcGpioCfg.enPu = GpioPuEnable; //端口上拉配置 GPIO上拉
stcGpioCfg.enCtrlMode = GpioAHB; //端口输入输出寄存器总线控制模式配置 AHB 总线控制模式
stcGpioCfg.enDrv = GpioDrvH; //端口驱动能力配置 GPIO高驱动能力
stcGpioCfg.enOD = GpioOdDisable; //端口开漏配置 GPIO开漏输出关闭
stcGpioCfg.enPd = GpioPdDisable; //端口下拉配置 GPIO无下拉
Gpio_Init(GpioPortA, GpioPin2, &stcGpioCfg);
Gpio_SetAfMode(GpioPortA, GpioPin2, GpioAf1); //配置TX
///<RX
stcGpioCfg.enDir = GpioDirIn; //端口方向配置 输入
stcGpioCfg.enPu = GpioPuEnable; //端口方向配置 GPIO上拉
stcGpioCfg.enCtrlMode = GpioAHB; //端口输入输出寄存器总线控制模式配置 AHB 总线控制模式
stcGpioCfg.enDrv = GpioDrvL; //端口驱动能力配置 GPIO低驱动能力
stcGpioCfg.enOD = GpioOdDisable; //端口开漏配置 GPIO开漏输出关闭
stcGpioCfg.enPd = GpioPdDisable; //端口下拉配置 GPIO无下拉
Gpio_Init(GpioPortA, GpioPin3, &stcGpioCfg);
Gpio_SetAfMode(GpioPortA, GpioPin3, GpioAf1); //配置RX
}
对于串口的中断我们需要注意,在初始化时,一定要先关闭串口发送中断使能。在后面需要时才打开。
static void Uart1_Config(void);
static void Uart1_PortInit(void);
#define U0_TX_MAX 500
uint8_t U0_TX_BUF[U0_TX_MAX]={0}; //串口发送缓存区
volatile uint16_t U0_TX_Cnt = 0;
uint8_t U0_TX_Index = 0; //串口发送索引
volatile uint8_t U0_TX_BUSY = 0;
int32_t main(void)
{
Uart1_Config(); //usrt1功能配置
Uart1_PortInit(); //usrt1引脚配置
UART1_SendStr("123");//测试
UART1_SendStr("456");//测试
UART1_SendStr("789");//测试
while(1)
{
}
}
void UART1_SendStr( unsigned char *str )
{
if( U1_TX_BUSY == 0) //串口发送空闲
{
U1_TX_Index = 0; //串口发送起始索引为0
U1_TX_BUSY = 1; //串口1繁忙标志置 1
U1_TX_Cnt = 0; //清除缓存
memset(U1_TX_BUF, 0, sizeof(U1_TX_BUF));
do
{
U1_TX_BUF[U1_TX_Cnt] = *(str + U1_TX_Cnt); //数据放入到缓存
U1_TX_Cnt++;
} while(*(str+U1_TX_Cnt) != '\0');
//开启串口发送中断
Uart_EnableIrq(M0P_UART1,UartTxEIrq); ///<使能串口1 Txe 发送缓存寄存器空 中断
Uart_DisableIrq(M0P_UART1,UartTxIrq); ///<关闭串口1 Tx 发送 中断
//这里注意当使能Txe而不是Tx时,不用先往发送缓存寄存器中放数据就能进入到串口1中断函数
//M0P_UART1->SBUF_f.DATA = U1_TX_BUF[0]; //当BUF有数据时,TXE硬件置0表示BUF非空
}
else if( U1_TX_BUSY == 1) //串口发送繁忙
{
while(1) //死等待 直到串口1发送空闲
{
if( U1_TX_BUSY ==0)
{
break;
}
}
if( U1_TX_BUSY == 0)//串口1发送空闲
{
U1_TX_Index = 0; //串口发送起始索引为0
U1_TX_BUSY = 1; //串口1繁忙标志置 1
U1_TX_Cnt = 0; //清除缓存
memset(U1_TX_BUF, 0, sizeof(U1_TX_BUF));
do
{
U1_TX_BUF[U1_TX_Cnt] = *(str + U1_TX_Cnt); //数据放入到缓存
U1_TX_Cnt++;
} while(*(str+U1_TX_Cnt) != '\0');
//开启串口发送中断
Uart_EnableIrq(M0P_UART1,UartTxEIrq); ///<使能串口1 Txe 发送缓存寄存器空 中断
Uart_DisableIrq(M0P_UART1,UartTxIrq); ///<关闭串口1 Tx 发送 中断
}
}
}
void UART1_SendData( unsigned char *str ,uint16_t count )
{
if( U1_TX_BUSY == 0) //串口发送空闲
{
U1_TX_Index = 0; //串口发送索引为第2位
U1_TX_BUSY = 1; //串口1繁忙标志置 1
U1_TX_Cnt = 0; //清除缓存
memset(U1_TX_BUF, 0, sizeof(U1_TX_BUF));
do
{
U1_TX_BUF[U1_TX_Cnt] = *(str + U1_TX_Cnt); //数据放入到缓存
U1_TX_Cnt++;
} while(U1_TX_Cnt < count);
//开启 串口发送寄存器空 中断
Uart_EnableIrq(M0P_UART1,UartTxEIrq); ///<使能串口1 Txe 中断
Uart_DisableIrq(M0P_UART1,UartTxIrq); ///<使能串口1 Tx 发送中断
return ;
}
else if( U1_TX_BUSY == 1) //串口发送繁忙
{
while(1)
{
if( U1_TX_BUSY ==0)
{
break;
}
}
if( U1_TX_BUSY == 0)//串口发送空闲
{
U1_TX_Index = 0; //串口发送索引为第2位
U1_TX_BUSY = 1; //串口1繁忙标志置 1
U1_TX_Cnt = 0; //清除缓存
memset(U1_TX_BUF, 0, sizeof(U1_TX_BUF));
do
{
U1_TX_BUF[U1_TX_Cnt] = *(str + U1_TX_Cnt); //数据放入到缓存
U1_TX_Cnt++;
} while(U1_TX_Cnt < count);
//开启 串口发送寄存器空 中断
Uart_EnableIrq(M0P_UART1,UartTxEIrq); ///<使能串口1 Txe 中断
Uart_DisableIrq(M0P_UART1,UartTxIrq); ///<使能串口1 Tx 发送中断
}
}
}
void Uart1_IRQHandler(void)
{
if(Uart_GetStatus(M0P_UART1, UartRC)) //UART1数据接收
{
Uart_ClrStatus(M0P_UART1, UartRC); //清中断状态位
}
//当ISR.TXE = 0 表示当前发送缓存满, SBUF不能写入数据
//当ISR.TXE = 1 表示当前发送缓存无数据,SBUF能写入数据
//TXE == 1表示缓存空
if(Uart_GetStatus(M0P_UART1, UartTxe) == 1)
{
if( U1_TX_Index < U1_TX_Cnt)
{
M0P_UART1->SBUF_f.DATA = U1_TX_BUF[U1_TX_Index]; //发送数据
U1_TX_Index++;
}
}
if(Uart_GetStatus(M0P_UART1, UartTC) == 1) //TC =1表示发送完毕
{
if( U1_TX_Index == U1_TX_Cnt ) //串口发送完最后一个字符
{
U1_TX_BUSY =0; //串口发送标志位置0 空闲
Uart_DisableIrq(M0P_UART1,UartTxEIrq); ///<关闭串口TC发送中断
}
}
}
这里的逻辑是当第一次发送数据(0x31,0x32,0x33)时,串口TX一定是空闲的,我们将串口置为繁忙,填充数据到串口缓存,之后开启串口发送缓存寄存器空 中断。一但开启(由于TXbuffer这时一定为空)直接进入 void Uart1_IRQHandler(void)
注意:关闭串口发送中断 不等于 无法判断标志位 ,或者说 关闭串口发送中断 不等于 标志位不会改变。(中断使能寄存器和标志位寄存器不是同一个)这是我们在Uart1_IRQHandler 去判断两个发送标志位的前提。
1进入if(Uart_GetStatus(M0P_UART1, UartTxe) == 1)
判断if( U1_TX_Index < U1_TX_Cnt)
满足,发送0x31
2进入if(Uart_GetStatus(M0P_UART1, UartTC) == 1)
判断if( U1_TX_Index == U1_TX_Cnt)
不满足,退出
3进入if(Uart_GetStatus(M0P_UART1, UartTxe) == 1)
判断if( U1_TX_Index < U1_TX_Cnt)
满足,发送0x32
4进入if(Uart_GetStatus(M0P_UART1, UartTC) == 1)
判断if( U1_TX_Index == U1_TX_Cnt)
不满足,退出
5进入if(Uart_GetStatus(M0P_UART1, UartTxe) == 1)
判断if( U1_TX_Index < U1_TX_Cnt)
满足,发送0x33
6进入if(Uart_GetStatus(M0P_UART1, UartTC) == 1)
判断if( U1_TX_Index == U1_TX_Cnt)
满足,U1_TX_BUSY 置0 ,关闭Txe串口发送寄存器空 中断
7.进入if(Uart_GetStatus(M0P_UART1, UartTxe) == 1)
判断if( U1_TX_Index < U1_TX_Cnt)
不满足,退出
8.退出Uart1_IRQHandler。至此UART1_SendStr("123");执行完毕
因篇幅问题不能全部显示,请点此查看更多更全内容