MSP430中printf()重定向输出

Posted 这还能重名?

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MSP430中printf()重定向输出相关的知识,希望对你有一定的参考价值。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、时钟配置

#include "clock.h"



//主系统目标时钟频率(单位kHz)
#define MCLK_target_kHz     25000

//主系统时钟频率与FLL源的比值
#define MCLK_inFLL_Ratio    763

uint16_t status;//振荡器状态标志



void clock_init(void)
{

    PMM_setVCore(PMM_CORE_LEVEL_1);//设置核心电压
    PMM_setVCore(PMM_CORE_LEVEL_2);
    PMM_setVCore(PMM_CORE_LEVEL_3);

    //XT1晶振输入引脚
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,GPIO_PIN4+GPIO_PIN5);
    //在低频模式下初始化XT1晶体振荡器
    UCS_turnOnLFXT1(UCS_XT1_DRIVE_0,UCS_XCAP_3);

//    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1,GPIO_PIN0);//辅助时钟输出引脚
//    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2,GPIO_PIN2);//子系统时钟输出引脚
//    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P7,GPIO_PIN7);//主系统时钟输出引脚

    //FLL的时钟来源为不分频的内部低频振荡器(32.768kHz)
    UCS_initClockSignal(UCS_FLLREF,UCS_XT1CLK_SELECT,UCS_CLOCK_DIVIDER_1);
    //辅助时钟的来源为不分频的内部振荡器
    UCS_initClockSignal(UCS_ACLK,UCS_XT1CLK_SELECT,UCS_CLOCK_DIVIDER_1);
    //子系统的时钟为主时钟的一半
    UCS_initClockSignal(UCS_SMCLK,UCS_DCOCLK_SELECT,UCS_CLOCK_DIVIDER_2);

    //设置主时钟的频率(单位kHz)和比率,初始化DCO
    UCS_initFLLSettle(MCLK_target_kHz,MCLK_inFLL_Ratio);

    SFR_clearInterrupt(SFR_OSCILLATOR_FAULT_INTERRUPT);//清除振荡器故障中断标志
    SFR_enableInterrupt(SFR_OSCILLATOR_FAULT_INTERRUPT);//开启振荡器故障中断

    __bis_SR_register(GIE);//使能全局中断

}

#pragma vector=UNMI_VECTOR
__interrupt void NMI_ISR(void)
{
    do
    {
        status = UCS_clearAllOscFlagsWithTimeout(1000);
    }while(status != 0);
}

首先对时钟的配置,如上所示,当频率高于12MHz的时候,提高核心电压的等级,否则产生的时钟不稳定,需要注意的是,需要一级一级的提升,不能一开始就提高到3级,代码中使用了外部的XTI(32.768KHz)作为时钟源,原因是内部晶振不稳定,受温度的影响大,而外部的晶振比较稳定。特别是涉及到通信的时候,晶振的不稳定会对通信产生很大的影响。


二、串口配置

#include "usart.h"


int fputc(int ch,FILE *f)
{
    USCI_A_UART_transmitData(USCI_A0_BASE,(uint8_t)ch);
    while(USCI_A_UART_getInterruptStatus(USCI_A0_BASE,USCI_A_UART_TRANSMIT_INTERRUPT_FLAG) == UCTXIFG);
    return ch;
}

int fputs(const char *_ptr,register FILE *_fp)
{
    uint16_t i,len;
    len = strlen(_ptr);
    for(i=0;i<len;i++)
    {
        USCI_A_UART_transmitData(USCI_A0_BASE,(unsigned char)_ptr[i]);
        while(USCI_A_UART_getInterruptStatus(USCI_A0_BASE,USCI_A_UART_TRANSMIT_INTERRUPT_FLAG) == UCTXIFG);
    }
    return len;
}

void usart_init(uint32_t clock,uint32_t baud)
{

    double clockPrescalar_val_temp,secondModReg_val_temp;
    uint16_t clockPrescalar_val,secondModReg_val;

    clockPrescalar_val_temp = (double)((clock * 1.0)/(baud * 1.0));
    clockPrescalar_val = (uint16_t)(clockPrescalar_val_temp);
    secondModReg_val_temp = (clockPrescalar_val_temp - clockPrescalar_val * 1.0) * 8;
    secondModReg_val = (uint16_t)(secondModReg_val_temp) + 1;
    if( (secondModReg_val_temp+0.5) >= secondModReg_val)
    {
        secondModReg_val = secondModReg_val;
    }
    else
    {
        secondModReg_val = secondModReg_val - 1;
    }

    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3,GPIO_PIN3 + GPIO_PIN4);//输出复用

    USCI_A_UART_initParam param = {0};
    param.clockPrescalar = clockPrescalar_val;//1.048MHz/9600取整
    param.firstModReg = 0;//过采样波特率时使用
    param.msborLsbFirst = USCI_A_UART_LSB_FIRST;//LSB
    param.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;//一个停止位
    param.overSampling = USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION;//低采样波特率
    param.parity = USCI_A_UART_NO_PARITY;//无奇偶校验位
    param.secondModReg = secondModReg_val;// {(1.048MHz/9600)-int(1.048MHz/9600)} * 8 = val ,然后再对val四舍五入取整。
    param.selectClockSource =USCI_A_UART_CLOCKSOURCE_SMCLK;//串口时钟的来源来自子系统时钟
    param.uartMode = USCI_A_UART_MODE;//串口模式

#if Tx_Interrupt
    USCI_A_UART_enableInterrupt(USCI_A0_BASE,USCI_A_UART_TRANSMIT_INTERRUPT);//开启串口发送中断
#endif

#if Rx_Interrupt
    USCI_A_UART_enableInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT);//开启串口接收中断
#endif

    if (STATUS_FAIL == USCI_A_UART_init(USCI_A0_BASE, &param))
   {
       return;
   }//等待串口模块初始化完成

    USCI_A_UART_clearInterrupt(USCI_A0_BASE,USCI_A_UART_TRANSMIT_INTERRUPT_FLAG);//清除串口发送完成标志
    USCI_A_UART_clearInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT_FLAG);//清除串口接收完成标志

    USCI_A_UART_enable(USCI_A0_BASE);//使能串口模块

}


#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR (void)
{

    switch (__even_in_range(UCA0IV,4))
   {
       case 0:break;//没有中断
       case 2:
           {
               USCI_A_UART_clearInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT_FLAG);
           };break;//接收中断
       case 4:
           {
               USCI_A_UART_clearInterrupt(USCI_A0_BASE,USCI_A_UART_TRANSMIT_INTERRUPT_FLAG);
           };break;//发送中断
       default: break;
   }

}

此处需要注意的地方有两点。第一,需要开启串口的发送中断和接收中断,否则串口不工作(未找到原因)。第二,在使用printf()重定向时,初始化的顺序尤其重要!!!

我们将上面正确的初始化程序调整一下,运行的结果如下图所示:


可以看出出现了乱码。当使用串口打印中文时,会出现乱码,很大的可能是CCS使用的编码格式和串口助手使用的编码格式不同。
修改工程的编码格式如下:
选中工程右键选择最底部的Properties选项(或者快捷键ALT+Enter),

以上是关于MSP430中printf()重定向输出的主要内容,如果未能解决你的问题,请参考以下文章

MSP430 中断

MSP430 中断

MSP430 中断

msp430项目编程30

将 printf 重定向到 UART 时,输出行呈阶梯状

msp430项目编程25