串口通信的配置
串口的配置 主要包括两个方面:
- 初始化结构体的配置
- 串口模块中断的开启
以下是基于DriverLib的初始化代码
const eUSCI_UART_Config uartConfig =
{
EUSCI_A_UART_CLOCKSOURCE_SMCLK, // SMCLK Clock Source 48Mhz
312, // BRDIV = 312
8, // UCxBRF = 8
0xAA, // UCxBRS = 0xAA
EUSCI_A_UART_NO_PARITY, // No Parity
EUSCI_A_UART_LSB_FIRST, // MSB First
EUSCI_A_UART_ONE_STOP_BIT, // One stop bit
EUSCI_A_UART_MODE, // UART mode
EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION // overSampling Mode
};
/* Configuring UART Module */
UART_initModule(EUSCI_A0_BASE, &uartConfig);
/* Enable UART module */
UART_enableModule(EUSCI_A0_BASE);
UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
Interrupt_enableInterrupt(INT_EUSCIA0);
MAP_Interrupt_enableSleepOnIsrExit(); //低功耗模式
比较困难的地方在于波特率的设置主要涉及到BRDIV,UCxBRF,UCxBRS, overSampling Mode这几个寄存器参数。
DriverLib手册中提到了一个参数计算器 http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html
如果上位机可以接收到FF FE之类的乱码一般是波特率设置不正确导致,不同的时钟源频率需要将其分离成所需要的频率,具体的计算公式在Reference Manual 的22.3.10小节有详细说明,将计算出来的波特率只要与上位机设置的相差不远也是可以进行通信的。
此外,网上有一部分相关帖子提到中断名的问题在CCS里边,系统会为所有中断定义一个默认中断,如果程序没有定义相关中断,在程序中又开启了此中断,中断触发后将会陷入到默认中断中。这里的默认中断内容是一个死循环,中断向量表在startup_msp432p401r_ccs.c
中有定义。
//Configure UART pins
P1SEL0 |=BIT2 | BIT3; // set2-UART pin as second function
__enable_interrupt();
NVIC->ISER[0] = 1 << ((EUSCIA0_IRQn) & 31); // EnableeUSCIA0 interrupt in NVIC module
//Configure UART
UCA0CTLW0|= UCSWRST;
UCA0CTLW0|= UCSSEL__SMCLK; // PuteUSCI in reset
// BaudRate calculation
//12000000/(16*9600) = 78.125
//Fractional portion = 0.125
// User'sGuide Table 21-4: UCBRSx = 0x10
// UCBRFx =int ( (78.125-78)*16) = 2
UCA0BR0 =78; //12000000/16/9600
UCA0BR1 =0x00;
UCA0MCTLW= 0x1000 | UCOS16 | 0x0020; //注意这一行的设定
UCA0CTLW0&= ~UCSWRST; //Initialize eUSCI
UCA0IE |=UCRXIE; // EnableUSCI_A0 RX interrupt
近几年来使用DriverLib开发的越来越多了,个人认为DriverLib可以在一定程度上简化开发流程,对新手友好,上手快,但是由于432官方对DriverLib手册并不是非常的友好,很多函数仅仅是一带而过,函数说明甚至没有源码注释写得好,这一使得学习432的内容需要齐头并进,能够简单易懂的用DriverLib难一些的还是要参考寄存器配置。
以下是串口中断处理函数,利用寄存器操作,将收到的串口数据进行回传。
/*
* EUSCI A0 UART interrupt handler.
*/
void EUSCIA0_IRQHandler(void)
{
if(UCA0IFG & UCRXIFG)
{
while(!(UCA0IFG&UCTXIFG));
UCA0TXBUF = UCA0RXBUF;
__no_operation();
}
}
而DriverLib版:
int receiveByte;
receiveByte = UART_receiveData(EUSCI_A0_BASE);
UART_transmitData(EUSCI_A0_BASE,receiveByte);
DriverLib的底层实现也是通过寄存器来完成的,这样可以通过学习源代码的方式了解某些寄存器的功能,省略某些技术细节,随着处理器执行效率的提高,代码越来越复杂,这样的库函数操作将会非常常见。
Comments