三 普通串口通信
我程序中的通信采用的是中断接收单字节,在主函数里面用一个函数来进行数据处理,比如校验等操作。
其实单片机的通信大致都是,时钟配置,IO口配置,打开io口时钟,打开串口时钟,将引脚配置成串口功能,然后设置中断以及初始化配置,只要初始化成功,几乎参照例程中的收发数据就能完成通信,然后再根据自己的需求来删减增加代码。
针对以往遇到的问题,现在再看来,可以将通信总结为:
- 初始化串口【几乎和例程中的Uartx_Init(UARTx);一致】:上代码:
void Uartx_Init(UARTx_Type* UARTx,uint32 Bounds)
{
UART_SInitTypeDef UART_para;
RCC_ClocksType RCC_Clocks;
volatile uint08 tmp08;
RCC_PERCLK_SetableEx(UARTCOMCLK, ENABLE); //UART0~5共享寄存器时钟使能
tmp08 = ((uint32_t)UARTx - UART0_BASE)>>5; //获取uart
switch(tmp08)
{
case 0:
RCC_PERCLK_SetableEx(UART0CLK, ENABLE); //UARTx时钟使能
// UART0 IO 配置
AltFunIO(GPIOF, GPIO_Pin_3, 0); //PF3 UART0 RX
AltFunIO(GPIOF, GPIO_Pin_4, 0); //PF4 UART0 TX
/*NVIC中断配置*/
NVIC_DisableIRQ(UART0_IRQn);
NVIC_SetPriority(UART0_IRQn,0); //中断优先级配置,与上位机通信/唤醒优先级最高
NVIC_EnableIRQ(UART0_IRQn);
break;
case 1:
RCC_PERCLK_SetableEx(UART1CLK, ENABLE); //UARTx时钟使能
// UART1 IO 配置
AltFunIO(GPIOB, GPIO_Pin_0, 0); //PB0 UART1 RX
AltFunIO(GPIOB, GPIO_Pin_1, 0); //PB1 UART1 TX
/*NVIC中断配置*/
NVIC_DisableIRQ(UART1_IRQn);
NVIC_SetPriority(UART1_IRQn,1); //中断优先级配置,与FPGA通信的优先级第二
NVIC_EnableIRQ(UART1_IRQn);
break;
case 2:
RCC_PERCLK_SetableEx(UART2CLK, ENABLE); //UARTx时钟使能
// UART2 IO 配置
AltFunIO(GPIOB, GPIO_Pin_2, 0); //PB2 UART2 RX
AltFunIO(GPIOB, GPIO_Pin_3, 0); //PB3 UART2 TX
/*NVIC中断配置*/
NVIC_DisableIRQ(UART2_IRQn);
NVIC_SetPriority(UART2_IRQn,1);//中断优先级配置
NVIC_EnableIRQ(UART2_IRQn);
break;
case 3:
RCC_PERCLK_SetableEx(UART3CLK, ENABLE); //UARTx时钟使能
// UART3 IO 配置
AltFunIO(GPIOC, GPIO_Pin_10, 0); //PC10 UART3 RX
AltFunIO(GPIOC, GPIO_Pin_11, 0); //PC11 UART3 TX
/*NVIC中断配置*/
NVIC_DisableIRQ(UART3_IRQn);
NVIC_SetPriority(UART3_IRQn,3);//中断优先级配置
NVIC_EnableIRQ(UART3_IRQn);
break;
case 4:
RCC_PERCLK_SetableEx(UART4CLK, ENABLE); //UARTx时钟使能
// UART4 IO 配置
AltFunIO(GPIOD, GPIO_Pin_0, 0); //PD0 UART4 RX
AltFunIO(GPIOD, GPIO_Pin_1, 0); //PD1 UART4 TX
//仅100脚
//AltFunIO(GPIOD, GPIO_Pin_9, 0); //PD9 UART4 RX
//AltFunIO(GPIOD, GPIO_Pin_10, 0); //PD10 UART4 TX
/*NVIC中断配置*/
NVIC_DisableIRQ(UART4_IRQn);
NVIC_SetPriority(UART4_IRQn,3);//中断优先级配置
NVIC_EnableIRQ(UART4_IRQn);
break;
case 5:
RCC_PERCLK_SetableEx(UART5CLK, ENABLE); //UARTx时钟使能
// UART5 IO 配置
AltFunIO(GPIOC, GPIO_Pin_4, 0); //PC4 UART5 RX
AltFunIO(GPIOC, GPIO_Pin_5, 0); //PC5 UART5 TX
/*NVIC中断配置*/
NVIC_DisableIRQ(UART5_IRQn);
NVIC_SetPriority(UART5_IRQn,3);//中断优先级配置
NVIC_EnableIRQ(UART5_IRQn);
break;
default:
break;
}
//UART初始化配置
UART_para.BaudRate = Bounds; //波特率
UART_para.DataBit = Eight8Bit; //数据位数
UART_para.ParityBit = NONE; //奇偶校验
UART_para.StopBit = OneBit; //停止位
RCC_GetClocksFreq(&RCC_Clocks); //获取APB时钟频率
UART_SInit(UARTx, &UART_para, RCC_Clocks.APBCLK_Frequency); //初始化uart
}
2、测试串口,直接,打开接收使能,打开发送使能,打开发送中断,打开接收中断。这个可以直接放在初始化串口成功后。例程中的其他的都是为了测试串口是否通,如果通了就只需要保留这四句就好。当然这是因为我发送函数是单独写的。发送函数配置其实和测试函数差不多,直接上代码:
void SendtoComputer(uint08 *Buffer,uint08 Len)
{
volatile uint08 UartNum;
UartNum = ((uint32_t)UART0 - UART0_BASE)>>5; //串口0发送
UARTx_RXSTA_RXEN_Setable(UART0, ENABLE); //打开接收使能
UARTx_TXSTA_TXEN_Setable(UART0, ENABLE); //打开发送使能
//中断发送数组
UARTxOp[UartNum].TxBuf = Buffer;
UARTxOp[UartNum].TxLen= Len;
UARTxOp[UartNum].TxOpc = 1;
UART_UARTIF_RxTxIF_ClrEx(UART0); //清除发送中断标志
UART_UARTIE_RxTxIE_SetableEx(UART0, TxInt, ENABLE);//打开发送中断
UARTx_TXREG_Write(UART0,UARTxOp[UartNum].TxBuf[0]); //发送第一个数据启动发送 ,中断转发接收到的数据
UARTx_RXSTA_RXEN_Setable(UART0, ENABLE); //打开接收使能
UART_UARTIE_RxTxIE_SetableEx(UART0, RxInt, ENABLE);//打开接收中断
}
3、中断里面几乎不用改,就在接收中断里面增加表示已接收到字节的状态标志,因为我是将数据处理放在了中断外。其他的就自由发挥了。
注1:如果在中断中发送字符/数组,串口助手测试时,显示字符/数组总是会多,也许是在最后多几个字符。
思路:观察定义中断发送数组中的长度是否定义不到位,直接定义成接收到的数组长度一般就正确了。也最好不要定义为(sizeof(buffer)/sizeof(buffer[0])这样的,因为你接收到的字节长度也许和你定义的数组长度不符。我就会定义一个32字节长度的buffer,去接收不定长的数据。
注2:在只能接收一次数据,接收不到第二次数据的时候,注意观察,是否在发送完数据之后打开接收使能和接收中断,不然就只能接收一次。