MSP430F5529库函数学习——串口

简介: MSP430F5529库函数学习——串口

首先,我们看MSP430F5529的库函数里面,会发现有两个跟串口有关的头文件"eusci_a_uart.h"和"usci_a_uart.h"。我查阅了资料后发现,其实就是一个普通的串行通讯模块,一个是增强型串行通讯模块。然后寄存器不太一样。我看TI的例程里面用的是"usci_a_uart.h"里面的函数,我就也只讲这给里面的了。        


GPIO_setAsPeripheralModuleFunctionInputPin()和GPIO_setAsPeripheralModuleFunctionOutputPin

大家一看,这个不是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 ()这一个函数就可以了。


参数

selectedPort

//!        - \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


selectedPins

//!        - \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);


USCI_A_UART_init()

函数声明

可能有人不知道bool是什么意思,bool就是布尔值,将人话就是0和非0。要么为真,要么为假,只有两种状态,这称之为布尔值。而非0就是1。

bool USCI_A_UART_init (uint16_t baseAddress,USCI_A_UART_initParam ∗ param )

作用

初始化串口

参数

baseAddress

说实话,TI这个老6库函数手册里面就一句话is the base address of the USCI_A_UART module。我尼玛怎么知道他们的地址。于是我找了一段时间,找到了以下参数,只有两个。

USCI_A0_BASE    //串口0基地址
USCI_A1_BASE    //串口1基地址


param

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 ;

USCI_A_UART_enable()


函数声明

 void USCI_A_UART_enable (uint16_t baseAddress )


作用

使能UART。

参数

baseAddress

串口基地址,参数下面两个

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);


USCI_A_UART_clearInterrupt()

函数声明

void USCI_A_UART_clearInterrupt (uint16_t baseAddress,uint8_t mask )

作用

清除UART中断标志位

参数

baseAddress

与上面一样,懒得再啰嗦

mask

就一个是接收中断,一个是发送中断。注意,我们发送数据一般是不需要中断,如果是发送一连串字符就需要了。但是接收数据一定要中断处理,这样能高效准确处理接收到的数据


参数就两个

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_enableInterrupt()

与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);   //使能接收和发送中断


串口中断函数

中断函数中的switch

因为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;
    }
}


printf函数支持

printf函数

拜读了大佬的博客。MSP430F5529的重定向fputc(int ch, FILE *f)直接使用printf的方法只有字符串和%s打印正常,数字打印不出来。所以采用下面这个

//这三个头文件都要加上,不然会报错
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
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

然后是build——>Advanced Options


实验

以下就是串口0将接收到的数据发送出去。同时每个1s给上位机发送一串字符。

#include "driverlib.h"
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#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, &param1)){
       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, &param1)){
        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;
    }
}


串口1所在位置

可能有些人发现P4.4和P4.5位置找不到,其实是在开发板这个地方。这里有跳线帽连着,需要把跳线帽摘下来,然后连接上USB转串口的模块。

目录
相关文章
|
16小时前
|
C++ 芯片 编译器
STM32F103标准外设库—— 新建工程与库函数(四)
STM32F103标准外设库—— 新建工程与库函数(四)
51 0
STM32F103标准外设库—— 新建工程与库函数(四)
|
7月前
STM32串口编程基础知识讲解
STM32串口编程基础知识讲解
60 0
|
16小时前
|
存储 传感器
【STM32基础 CubeMX】uart串口通信
【STM32基础 CubeMX】uart串口通信
154 0
|
11月前
|
缓存
STM32使用HAL库实现串口通讯——实战操作
STM32使用HAL库实现串口通讯——实战操作
195 0
|
11月前
|
缓存 Go
STM32使用HAL库实现串口通讯——理论讲解
STM32使用HAL库实现串口通讯——理论讲解
280 0
|
11月前
MSP430F5529库函数GPIO学习
MSP430F5529库函数GPIO学习
94 0
|
11月前
|
开发工具 git
MSP430F5529库函数定时器A——硬件PWM
MSP430F5529库函数定时器A——硬件PWM
133 0
|
11月前
MSP430F5529库函数定时器B
MSP430F5529库函数定时器B
86 0
|
11月前
|
存储 芯片
MSP430F5529库函数——模数转换模块(ADC12)软件触发
MSP430F5529库函数——模数转换模块(ADC12)软件触发
166 0