波特率计算网站;导入MSP430Ware,查看例程;原理图和中文开发手册获取
目录
GPIO_setAsPeripheralModuleFunctionInputPin()和GPIO_setAsPeripheralModuleFunctionOutputPin
函数声明
作用
参数
selectedPort
selectedPins
使用
USCI_A_UART_init()
函数声明
作用
参数
baseAddress
param
USCI_A_UART_enable()
函数声明
作用
参数
baseAddress
使用
USCI_A_UART_clearInterrupt()
函数声明
作用
参数
baseAddress
mask
使用
USCI_A_UART_enableInterrupt()
串口中断函数
中断函数中的switch
串口中断服务函数框架
printf函数支持
printf函数
使用
浮点数据打印
实验
串口1所在位置
首先,我们看MSP430F5529的库函数里面,会发现有两个跟串口有关的头文件"eusci_a_uart.h"和"usci_a_uart.h"。我查阅了资料后发现,其实就是一个普通的串行通讯模块,一个是增强型串行通讯模块。然后寄存器不太一样。我看TI的例程里面用的是"usci_a_uart.h"里面的函数,我就也只讲这给里面的了。
大家一看,这个不是GPIO的函数吗?对的,不过你进行串口通讯需要用到他,我看手册里面说MSP430F5xx/6xx不具备这个功能,但是例程里面有,卡了我好久。我猜手册写错了。
void GPIO_setAsPeripheralModuleFunctionInputPin (uint8_t selectedPort,uint16_t selectedPins )
void GPIO_setAsPeripheralModuleFunctionOutputPin (uint8_t selectedPort,uint16_t selectedPins )
GPIO_setAsPeripheralModuleFunctionInputPin ()该函数在所选引脚的输入方向上配置外围模块函数。该函数为所选引脚的主、次或三元模块函数模式的输入方向配置外围模块函数。
GPIO_setAsPeripheralModuleFunctionOutputPin()该函数为所选引脚的输出方向配置外围模块函数。该函数在输出方向为所选引脚配置外围模块函数,用于主、次或三元模块函数模式。
这个是官方库函数手册翻译的结果,说实话我也看不懂,反正我们只需要用,知道用用法就行。
需要注意的一点就是,外设功能方向引脚看具体功能,有些外设不需要哦设置方向。例如uart,设置为引脚之后,系统会自动设置输入输出方向。所以我们直接选择GPIO_setAsPeripheralModuleFunctionInputPin ()这一个函数就可以了。
//! - \b GPIO_PORT_P1
//! - \b GPIO_PORT_P2
//! - \b GPIO_PORT_P3
//! - \b GPIO_PORT_P4
//! - \b GPIO_PORT_P5
//! - \b GPIO_PORT_P6
//! - \b GPIO_PORT_P7
//! - \b GPIO_PORT_P8
//! - \b GPIO_PORT_P9
//! - \b GPIO_PORT_P10
//! - \b GPIO_PORT_P11
//! - \b GPIO_PORT_PA
//! - \b GPIO_PORT_PB
//! - \b GPIO_PORT_PC
//! - \b GPIO_PORT_PD
//! - \b GPIO_PORT_PE
//! - \b GPIO_PORT_PF
//! - \b GPIO_PORT_PJ
//! - \b GPIO_PIN0
//! - \b GPIO_PIN1
//! - \b GPIO_PIN2
//! - \b GPIO_PIN3
//! - \b GPIO_PIN4
//! - \b GPIO_PIN5
//! - \b GPIO_PIN6
//! - \b GPIO_PIN7
//! - \b GPIO_PIN8
//! - \b GPIO_PIN9
//! - \b GPIO_PIN10
//! - \b GPIO_PIN11
//! - \b GPIO_PIN12
//! - \b GPIO_PIN13
//! - \b GPIO_PIN14
//! - \b GPIO_PIN15
//! - \b GPIO_PIN_ALL8
//! - \b GPIO_PIN_ALL16
MSP430F5529好像就两个串口,记住这下面两个就行,记不住收藏博客,需要用的时候过来抄。
需要注意,不需要我们像stm32那样配置3.4为输入,3.5为输出,直接像我下面这样写就可以了。
//Usart0 P3.4 = USCI_A0 RXD P3.3 = USCI_A0 TXD
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3, GPIO_PIN3+GPIO_PIN4);
//Usart1 P4.5 = USCI_A1 RXD P4.4 = USCI_A1 TXD
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4, GPIO_PIN5+GPIO_PIN4);
可能有人不知道bool是什么意思,bool就是布尔值,将人话就是0和非0。要么为真,要么为假,只有两种状态,这称之为布尔值。而非0就是1。
bool USCI_A_UART_init (uint16_t baseAddress,USCI_A_UART_initParam ∗ param )
初始化串口
说实话,TI这个老6库函数手册里面就一句话is the base address of the USCI_A_UART module。我尼玛怎么知道他们的地址。于是我找了一段时间,找到了以下参数,只有两个。
USCI_A0_BASE //串口0基地址
USCI_A1_BASE //串口1基地址
param是一个结构体,我娓娓道来。
(1)首先我先介绍 param1.selectClockSource,他是负责选择串口波特率发生时钟的。只有两个参数,ACLK= TACLK 32768Hz, MCLK= SMCLK= default DCO ~ 1048576Hz。
注意,对于较低的波特率(9600bps以下),可以选择ACLK作为时钟源(注意,是可以选择,不是只能选择)。在波特率高于9600bps的情况下,应选择频率较高的SMCLK作为时钟源。
USCI_A_UART_CLOCKSOURCE_SMCLK //1048576Hz
USCI_A_UART_CLOCKSOURCE_ACLK //32768Hz
(2)然后是这4个,这四个负责配置串口波特率的,至于传入数值怎么算呢?点击这个网站,先根据我们之前设置的时钟,USCI/EUSCI选择USCI,然后波特率你自己选。下面这个就是SMCLK时钟频率下,波特率为9600的配置。
param1.clockPrescalar = 6;
param1.firstModReg = 13;
param1.secondModReg = 0;
param1.overSampling = USCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION;
#define USCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION 0x01
#define USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION 0x00
(3)接下来这几个是选择,这三个都是基础。还有不清楚,你可以看一下你电脑端串口助手一般都有这几个要配置,你就按照我的来就可以了。然后下面这三个参数你也不用改,跟我的一样即可。
param1.parity = USCI_A_UART_NO_PARITY; //校验位,无
param1.msborLsbFirst = USCI_A_UART_LSB_FIRST; //数据低位先发
param1.numberofStopBits = USCI_A_UART_ONE_STOP_BIT; //一停止位
(4)最后一个参数 ,是用来配置串口模式的。就使用USCI_A_UART_MODE模式即可,其他几个我也不知道是做什么的。
param1.uartMode = USCI_A_UART_MODE;
详细解释,我们查看 USCI_A_UART_MODE定义发现还有三个其他的定义,而这四个定义本质如下
#define USCI_A_UART_MODE UCMODE_0
#define USCI_A_UART_IDLE_LINE_MULTI_PROCESSOR_MODE UCMODE_1
#define USCI_A_UART_ADDRESS_BIT_MULTI_PROCESSOR_MODE UCMODE_2
#define USCI_A_UART_AUTOMATIC_BAUDRATE_DETECTION_MODE UCMODE_3
#define UCMODE_0 (0x00) /* Sync. Mode: USCI Mode: 0 */
#define UCMODE_1 (0x02) /* Sync. Mode: USCI Mode: 1 */
#define UCMODE_2 (0x04) /* Sync. Mode: USCI Mode: 2 */
#define UCMODE_3 (0x06) /* Sync. Mode: USCI Mode: 3 */
我们查看USCI_A_UART_init()的内部函数实现,看到其实就算再操作UCAxCTL0这个寄存器,我们可以直接看手册。最后发现模式0,就是UART模式。模式1,空闲线路多处理器模式。模式2,地址位多处理器模式。模式3,自带动波特率检测UART模式。
注意,我们这个是UART模块,所以不能同步。
//Configure UART mode.
HWREG8(baseAddress + OFS_UCAxCTL0) |= param->uartMode ;
void USCI_A_UART_enable (uint16_t baseAddress )
使能UART。
串口基地址,参数下面两个
USCI_A0_BASE //串口0基地址
USCI_A1_BASE //串口1基地址
//Enable UART module for operation
USCI_A_UART_enable(USCI_A0_BASE);
//Enable UART module for operation
USCI_A_UART_enable(USCI_A1_BASE);
void USCI_A_UART_clearInterrupt (uint16_t baseAddress,uint8_t mask )
清除UART中断标志位
与上面一样,懒得再啰嗦
就一个是接收中断,一个是发送中断。注意,我们发送数据一般是不需要中断,如果是发送一连串字符就需要了。但是接收数据一定要中断处理,这样能高效准确处理接收到的数据。
参数就两个
USCI_A_UART_RECEIVE_INTERRUPT_FLAG //接收中断标志位
USCI_A_UART_TRANSMIT_INTERRUPT_FLAG //发送中断标志位
//Usart0
USCI_A_UART_clearInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT); //清除接收中断
USCI_A_UART_clearInterrupt(USCI_A0_BASE,USCI_A_UART_TRANSMIT_INTERRUPT); //清除发送中断
USCI_A_UART_clearInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT + USCI_A_UART_TRANSMIT_INTERRUPT); //清除接收和发送中断
//Usart1
USCI_A_UART_clearInterrupt(USCI_A1_BASE,USCI_A_UART_RECEIVE_INTERRUPT); //清除接收中断
USCI_A_UART_clearInterrupt(USCI_A1_BASE,USCI_A_UART_TRANSMIT_INTERRUPT); //清除发送中断
USCI_A_UART_clearInterrupt(USCI_A1_BASE,USCI_A_UART_RECEIVE_INTERRUPT + USCI_A_UART_TRANSMIT_INTERRUPT); //清除接收和发送中断
与USCI_A_UART_clearInterrupt参数与使用一摸一样。
作用是使能串口中断,使用方法如下
//Usart0
USCI_A_UART_enableInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT); //使能接收中断
USCI_A_UART_enableInterrupt(USCI_A0_BASE,USCI_A_UART_TRANSMIT_INTERRUPT); //使能发送中断
USCI_A_UART_enableInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT + USCI_A_UART_TRANSMIT_INTERRUPT); //使能接收和发送中断
//Usart1
USCI_A_UART_enableInterrupt(USCI_A1_BASE,USCI_A_UART_RECEIVE_INTERRUPT); //使能接收中断
USCI_A_UART_enableInterrupt(USCI_A1_BASE,USCI_A_UART_TRANSMIT_INTERRUPT); //使能发送中断
USCI_A_UART_enableInterrupt(USCI_A1_BASE,USCI_A_UART_RECEIVE_INTERRUPT + USCI_A_UART_TRANSMIT_INTERRUPT); //使能接收和发送中断
因为MSP430F5529的中断,是多个中断标志位公用同一个中断向量,所以我们需要加上Switch语句。如下
串口中断服务函数框架如下
注意,我们只需要在case 2:里面增加或者减少内容即可。
//UART0串口中断服务函数
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR (void)
{
uint8_t receivedData = 0;
switch (__even_in_range(UCA0IV,4))
{
//Vector 2 - RXIFG
case 2:
receivedData = USCI_A_UART_receiveData(USCI_A0_BASE);
USCI_A_UART_transmitData(USCI_A0_BASE,receivedData);
break;
default:
break;
}
}
//UART1串口中断服务函数
#pragma vector=USCI_A1_VECTOR
__interrupt void USCI_A1_ISR (void)
{
uint8_t receivedData = 0;
switch (__even_in_range(UCA1IV,4))
{
//Vector 2 - RXIFG
case 2:
receivedData = USCI_A_UART_receiveData(USCI_A1_BASE);
USCI_A_UART_transmitData(USCI_A1_BASE,receivedData);
break;
default:
break;
}
}
拜读了大佬的博客。MSP430F5529的重定向fputc(int ch, FILE *f)直接使用printf的方法只有字符串和%s打印正常,数字打印不出来。所以采用下面这个
//这三个头文件都要加上,不然会报错
#include
#include
#include
void UART_printf(uint16_t baseAddress, const char *format,...)
{
uint32_t length;
va_list args;
uint32_t i;
char TxBuffer[128] = {0};
va_start(args, format);
length = vsnprintf((char*)TxBuffer, sizeof(TxBuffer), (char*)format, args);
va_end(args);
for(i = 0; i < length; i++)
USCI_A_UART_transmitData(baseAddress, TxBuffer[i]);
}
函数使用方法很简单,和printf函数几乎一样。唯一区别是,此处的UART_printf需要提前告知是串口0还是串口1。
//串口0发送
UART_printf(USCI_A0_BASE, "数字测试:%d,字符串测试:%s\r\n", 2333, "能收到就算成功");
//串口1发送
UART_printf(USCI_A1_BASE, "数字测试:%d,字符串测试:%s\r\n", 2333, "能收到就算成功");
如果你不设置工程编译环境,那么你可能打印不出来浮点型数据。步骤如下:
右键工程文件——>properties
以下就是串口0将接收到的数据发送出去。同时每个1s给上位机发送一串字符。
#include "driverlib.h"
#include
#include
#include
#define CPU_F ((double)1000000)
#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0))
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))
void UART_printf(uint16_t baseAddress, const char *format,...)
{
uint32_t length;
va_list args;
uint32_t i;
char TxBuffer[128] = {0};
va_start(args, format);
length = vsnprintf((char*)TxBuffer, sizeof(TxBuffer), (char*)format, args);
va_end(args);
for(i = 0; i < length; i++)
USCI_A_UART_transmitData(baseAddress, TxBuffer[i]);
}
//9600
void Usart1_Init()
{
//P4.4=UCA1TXD P4.5=UCA1RXD
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4, GPIO_PIN5+GPIO_PIN4);
USCI_A_UART_initParam param1 = {0};
param1.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK;
param1.clockPrescalar = 6;
param1.firstModReg = 13;
param1.secondModReg = 0;
param1.parity = USCI_A_UART_NO_PARITY; //无校验位
param1.msborLsbFirst = USCI_A_UART_LSB_FIRST; //低位先行
param1.numberofStopBits = USCI_A_UART_ONE_STOP_BIT; //1停止位
param1.uartMode = USCI_A_UART_MODE;
param1.overSampling = USCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION;
if (STATUS_FAIL == USCI_A_UART_init(USCI_A1_BASE, ¶m1)){
return;
}
//Enable UART module for operation
USCI_A_UART_enable(USCI_A1_BASE);
//Enable Receive Interrupt
USCI_A_UART_clearInterrupt(USCI_A1_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
USCI_A_UART_enableInterrupt(USCI_A1_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
}
void Usart0_Init(void)
{
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3, GPIO_PIN3+GPIO_PIN4);
USCI_A_UART_initParam param1 = {0};
param1.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK;
param1.clockPrescalar = 6;
param1.firstModReg = 13;
param1.secondModReg = 0;
param1.overSampling = USCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION;
param1.parity = USCI_A_UART_NO_PARITY;
param1.msborLsbFirst = USCI_A_UART_LSB_FIRST;
param1.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;
param1.uartMode = USCI_A_UART_MODE;
if (STATUS_FAIL == USCI_A_UART_init(USCI_A0_BASE, ¶m1)){
return;
}
//Enable UART module for operation
USCI_A_UART_enable(USCI_A0_BASE);
//Enable Receive Interrupt
USCI_A_UART_clearInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
USCI_A_UART_enableInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
}
void main(void)
{
WDT_A_hold(WDT_A_BASE);
Usart0_Init();
//interrupts enabled
__bis_SR_register(GIE);
while(1)
{
UART_printf(USCI_A0_BASE, "数字测试:%d,字符串测试:%s\r\n", 2333, "能收到就算成功");
delay_ms(1000);
}
}
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR (void)
{
uint8_t receivedData = 0;
switch (__even_in_range(UCA0IV,4))
{
//Vector 2 - RXIFG
case 2:
receivedData = USCI_A_UART_receiveData(USCI_A0_BASE);
USCI_A_UART_transmitData(USCI_A0_BASE,receivedData);
break;
default:
break;
}
}
#pragma vector=USCI_A1_VECTOR
__interrupt void USCI_A1_ISR (void)
{
uint8_t receivedData = 0;
switch (__even_in_range(UCA1IV,4))
{
//Vector 2 - RXIFG
case 2:
receivedData = USCI_A_UART_receiveData(USCI_A1_BASE);
USCI_A_UART_transmitData(USCI_A1_BASE,receivedData);
break;
default:
break;
}
}
可能有些人发现P4.4和P4.5位置找不到,其实是在开发板这个地方。这里有跳线帽连着,需要把跳线帽摘下来,然后连接上USB转串口的模块。