MSP430F5529库函数学习——串口

波特率计算网站导入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_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转串口的模块。 

  • 34
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风正豪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值