This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

【21ic原创】【MSP430i2xx教程第二讲】时钟系统 & EUSCI_A_UART

Other Parts Discussed in Thread: MSP430G2231

第三章  时钟系统(CS

 

3.1  本章引言

  时钟系统(Clock System)模块支持低成本和低功耗。通过使用4个内部时钟信号,用户可以在低功耗和性能之间做到最好的平衡。
  时钟模块可以配置成无需任何外部组件,使用一个外部电阻器或完全使用DCO旁路模式。
  时钟模块有四个系统时钟信号可以使用:
  • ACLK:辅助时钟。当运行在DCO时,ACLK是固定在32kHz。如果设备是设置在DCO旁路模式,ACLK运行在旁路时钟频率的1/512
  • MCLK:主时钟。MCLK可以被1,2,4,816分频。MCLK通常被CPU和系统使用
  • SMCLK:子系统主时钟。SMCLK可以被1,2,4,816分频。SMCLK可以被各个外围模块通过软件选择使用。
  • SD24CLK:SD24时钟提供一个1.024MHz固定频率的时钟给Sigma-Delta ADC(SD24)。
  该时钟只为SD24的请求所使用。如果SD24功能必须在DCO旁路模式下工作,那么外部时钟频率必须是16.384Mhz
  这个驱动程序包含在cs.c文件里,cs.h头文件包含该应用程序使用的API定义

 

3.2  函数总览

  #define CS_DCO_FREQ  16384000
1
void GS_setupDCO ( uint8_t mode )
使用选中的模式配置DCO
2
void CS_initClockSignal (uint8_t clockSource, uint8_t clockSourceDivider)
使用分频器初始化时钟信号
3
uint32_t CS_getACLK (void)
获取当前ACLK的频率(单位Hz
4
uint32_t CS_getSMCLK (void)
获取当前SMCLK的频率(单位Hz
5
uint32_t CS_getMCLK (void)
获取当前MCLK的频率(单位Hz
6
uint8_t CS_getFaultFlagStatus (uint8_t mask)
获取DCO故障(或错误)标志状态
  CS API函数分为三组:配置时钟模块的、侦测时钟速度的和CS错误标记处理的。
  CS一般配置和初始化的函数有:
  • CS_setupDCO()
  • CS_initClockSignal()
  侦测时钟速度的函数有:
  • CS_getACLK()
  • CS_getSMCLK()
  • CS_getMCLK()
  CS错误标志处理的函数有
  • CS_getFaultFlagStatus()
  函数CS_getMCLK,CS_getSMCLK,CS_getACLK只在使用内部或外部电阻或者16.384MHz的旁路时钟频率下使用DCO才是精确有效的
详细描述
  uint32_t CS_getACLK(void)
  获取当前ACLK频率(单位Hz)。当设备安装在DCO旁路模式下,它不能正常工作。此外,使用这个API前应该调用CS_setupDCO(),以便DCO被校准,这样计算才是精确的。
  返回值:当前ACLK频率,单位Hz,当旁路模式下返回0
  uin8_t CS_getFaultFlagStatus(uint8_t mask)
  获取DCO错误标志状态。当DCO在外部电阻模式和DCO检测到异常时候,DCO故障标志将被置位(写1)。异常可能是,ROSC端子保持开路或者短接到地,或者连接在ROSC端子的电阻远离推荐的值。如果故障仍然存在,DCO就会自动切换到内部电阻模式作为一种处理故障的安全机制。
  mask:mask参数有CS_DCO_FAULT_FLAG.
  返回值:CS_DCO_FAULT_FLAG。说明错误标志被置位。
  uint32_t CS_getMCLK(void)
  获取当前MCLK频率(单位Hz)。当设备安装在DCO旁路模式下,它不能正常工作。此外,使用这个API前应该调用CS_setupDCO(),以便DCO被校准,这样计算才是精确的。
  返回值:当前MCLK频率,单位Hz,当旁路模式下返回0
  uint32_t CS_getSMCLK(void)
  获取当前SMCLK频率(单位Hz)。当设备安装在DCO旁路模式下,它不能正常工作。此外,使用这个API前应该调用CS_setupDCO(),以便DCO被校准,这样计算才是精确的。
  返回值:当前SMCLK频率,单位Hz,当旁路模式下返回0
  void CS_initClockSignal( uint8_t clockSource,  uint8_t clockSourceDivider )
  使用分频器初始化一个时钟信号。
  如果DCO是在旁路模式下,频率将是CLKIN/分频器。如果DCO不在旁路模式下,频率将是16.384MHz/分频器
  该函数有两个参数:clockSourceclockSourceDivider
  clockSource时钟信号初始化值可以选的值有:CS_MCLK,CS_SMCLK。
  clockSourceDivider分频器设置可选的值有CS_CLOCK_DIVIDER_1,CS_CLOCK_DIVIDER_2,CS_CLOCK_DIVIDER_4,CS_CLOCK_DIVIDER_8,CS_CLOCK_DIVIDER_16。
  返回值:无。
  void CS_setupDCO( uint8_t mode )
  使用参数所选模式配置DCO如果选择旁路模式,则需要在CLKIN管脚接入外部数字时钟信号来作为所有的设备(CPU、外设等)的时钟信号。ACLK频率是不可以被编程的,且固定在旁路时钟频率除以512。使用外部吊足模式,需要在ROSC管脚连接一个20KΩ的电阻器。与使用内部电阻相比,使用外部电阻模式,在绝对误差和温度漂移上,可以提供更高的时钟精度。请根据你所选的设备型号对应的数据手册的详细情况来选择不同的模式。
  该函数只有一个参数:mode。
  mode:该参数可以选择的量有CS_INTERNAL_RESISTOR,CS_EXTERNAL_RESISTOR,CS_BYPASS_MODE。
  返回值:空。
  注释:DCO的配置可以使用内部电阻和外部电阻,还有一个就是旁路模式,旁路模式就是可以通过一个时钟输入管脚将外部时钟信号灌入系统。
 
3.3  例程
  下面的例程演示如何配置CS模块,设置为SMCLK=DCO/2,MCLK=DCO/8。
//先配置DCO频率为16.384MHz.
CS_setupDCO(CS_INTERNAL_RESISTOR);
//配置完DCO才可以配置MCLKSMCLK
CS_initClockSignal(CS_MCLK,  CS_CLKOCK_DIVIDER_8);
CS_initClockSignal(CS_SMCLK,  CS_CLKOCK_DIVIDER_2);
MSP430I2XX+教程第二讲.pdf
  • 第四章  EUSCI通用异步接收器/发送器(EUSCI_A_UART

    4.1  本章引言

      MSP430i2xx系列的EUSC_A_UART驱动库特性包括
    • 奇偶校验或非奇偶校验
    • 独立的发送和接收移位寄存器
    • 分立的发送和接收缓冲寄存器
    • 低位优先或高位优先数据发送和接收
    • 内置空闲线和地址位通信协议的多处理器系统
    • 具有从LPMx模式自动唤醒接收器启动的边缘检测
    • 用于错误检测和抑制的状态标志
    • 地址检测的状态标志
    • 用于接收和发送独立的中断能力
      在UART模式中,eUSCI在一定的位速率下,异步与另外一个设备进行字符的发送和接收。每个字符的时间长度是基于所选择的eUSCI波特率所固定的。因此,发送和接收函数要使用相同的波特率进行通信。
      这个驱动程序包含在eusci_a_uart.c文件里eusci_a_uart.h头文件包含该应用程序使用的API定义

    4.2  函数总览

    1
    bool EUSCI_A_UART_init ( uint16_t baseAddress,EUSCI_A_UART_initParam *param )
    先进的UART模块初始化程序,把初始化参数通过初始化函数写进时钟预分频器。
    2
    void EUSCI_A_UART_transmitData (uint16_t baseAddress, uint8_t transmitData)
    UART模块发送出去一个字节
    3
    void EUSCI_A_UART_receiveData (uint16_t baseAddress)
    接收一个字节数据。
    4
    void EUSCI_A_UART_enableInterrupt (uint16_t baseAddress,uint8_t mask)
    使能UART(独立的)中断源
    5
    void EUSCI_A_UART_disableInterrupt (uint16_t baseAddress,uint8_t mask)
    关闭UART(独立的)中断源
    6
    void EUSCI_A_UART_getInterruptStatus (uint16_t baseAddress,uint8_t mask)
    获取当前UART中断状态
    7
    void EUSCI_A_UART_clearInterruptStatus (uint16_t baseAddress,uint8_t mask)
    清除UART中断源。(备注:清除中断状态,重置中断状态标识)
    8
    void EUSCI_A_UART_enable (uint16_t baseAddress)
    启用UART模块
    9
    void EUSCI_A_UART_disable (uint16_t baseAddress)
    关闭UART模块
    10
    uint8_t EUSCI_A_UART_queryStatusFlags (uint16_t baseAddress, uint8_t mask)
    获取当前UART状态标志.(查询UART当前状态标识)
    11
    void EUSCI_A_UART_setDormant(uint16_t baseAddress)
    UART模块设置在休眠模式
    12
    void EUSCI_A_UART_resetDormant(uint16_t baseAddress)
    UART模块从休眠模式唤醒
    13
    void EUSCI_A_UART_transmitAddress(uint16_t baseAddress,uint8_t transmitAddress)
    根据所选的多处理器模式,传送下一个字节标记为地址
    14
    void EUSCI_A_UART_transmitBreak(uint16_t baseAddress)
    发送终止
    15
    uint32_t EUSCI_A_UART_getReceiveBufferAddress(uint16_t baseAddress)
    返回RX缓冲区的UARTDMA模块的地址。
    16
    uint32_t EUSCI_A_UART_getTransmitBufferAddress(uint16_t baseAddress)
    返回TX缓冲区的UARTDMA模块的地址。
    17
    void EUSCI_A_UART_selectDeglitchTime(uint16_t baseAddress,uint16_t deglitchTime)
    设置抗尖峰脉冲时间
      EUSI_A_UART_API提供了一组函数,用来实现一个中断驱动EUSI_A_UART的驱动程序。该EUSI_A_UART初始化的各种模式和功能是由EUSCI_A_UART_init()完成。这个函数初始化结束EUSI_A_UART保持禁用(所有的相关配置工作完成后才会通过函数启动UART)。EUSCI_A_UART_enable()使EUSI_A_UART,模块现在已经可以准备传输和接收了。
      建议通过EUSCI_A_UART_init()初始化EUSI_A_UART,使能所需的中断,然后通EUSCI_A_UART_enable()启用EUSI_A_UART
      EUSI_A_UART API函数分为三组:那些处理EUSI_A_UART模块配置和控制的,用于发送和接收数据的,管理中断和状态的。
      配置和控制EUSI_UART的函数有:
    • EUSCI_UART_init()
    • EUSCI_UART_enable()
    • EUSCI_UART_disable()
    • EUSCI_UART_setDormant()
    • EUSCI_UART_resetDormant()
    • EUSCI_UART_selectDeglithTime()
      通过EUSI_UART发送和接收数据的函数有:
    • EUSCI_UART_transmitData()
    • EUSCI_UART_receiveData()
    • EUSCI_UART_transmitAddress()
    • EUSCI_UART_transmitBreak()
      管理EUSI_UART中断和状态的函数有
    • EUSCI_UART_enableInterrupt()
    • EUSCI_UART_disableInterrupt()
    • EUSCI_UART_geInterruptStatus()
    • EUSCI_UART_clearInterrupt()
    • EUSCI_UART_queryStatusFlags()
      void EUSCI_A_UART_clearInterruptStatus (uint16_t baseAddress,uint8_t mask)
        清除UART中断源
        UART中断源被清除,所以它不再断言(计算机专业术语,大概意思就是:中断源被清除后,相关的不再执行,根据我们所接触过的类似的情况,可以看出来,清除中断标志后,才可以重新接收新一次的中断信号,本次中断信号已经完成,不再有效)。
        该函数共两个参数:baseAddressmask
      参数
    baseAddress
    EUSCI_A_UART模块的基地址
    mask
    将被清除中断源的位掩码。掩码值可以是以下量的逻辑或:
    EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG
    EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG
    EUSCI_A_UART_STARTBIT_INTERRUPT_FLAG
    EUSCI_A_UART_TRANSMIT_COMPLETE_INTERRUPT_FLAG
        该函数修改UCAxIFG寄存器。
        返回值:无。
      void EUSCI_A_UART_disable (uint16_t baseAddress)
        关闭UART模块。
        该函数只有1个参数:baseAddress。
      参数
    baseAddress
    EUSCI_A_UART模块的基地址
        该函数修改UCAxCTL1寄存器的UCSWRST位。
        返回值:无。
      void EUSCI_A_UART_disableInterrupt (uint16_t baseAddress, uint8_t mask)
        关闭独立的UART中断源。
        禁用表示的UART中断源。只有启用的源可以反映给处理器进行中断。禁用的源不会影响到处理器的工作。
        该函数共两个参数:baseAddressmask
    参数
    baseAddress
    EUSCI_A_UART模块的基地址
    mask
    掩码位对应的中断源将会被关闭。掩码值可以是以下量的逻辑或:
    EUSCI_A_UART_RECEIVE_INTERRUPT                                 接收中断
    EUSCI_A_UART_TRANSMIT_INTERRUPT                                   发送中断
    EUSCI_A_UART_RECEIVE_ERRONEOUSCHAR_INTERRUPT   收到错误的字符中断使能
    EUSCI_A_UART_BREAKCHAR_INTERRUPT                     接收间隔字符中断使能
    EUSCI_A_UART_STARTBIT_INTERRUPT                           起始位接收中断启用
    EUSCI_A_UART_TRANSMIT_COMPLETE_INTERRUPT                   发送完成中断使
        该函数修改UCAxCTL1寄存器的UCAxIE位。
        返回值:无。
  •  void EUSCI_A_UART_enable(uint16_t baseAddress)

        启用UART模块,这将能够操作UART模块
        该函数只有1个参数:baseAddress。
      参数
    baseAddress
    EUSCI_A_UART模块的基地址
        该函数修改UCAxCTL1寄存器的UCSWRST位。
        返回值:无。
      void EUSCI_A_UART_enableInterrupt (uint16_t baseAddress, uint8_t mask)
        启用独立的UART中断源。
        只有这个源使能启用后才能够反映到处理器中断;关闭源将不再影响到处理器。
    注释:通过该函数启动中断源,才可以把中断事件产生的中标标志置位反映到处理器响应中断,进行中断,如果关闭了中断源,系统将不会把中断标志置位的信号传递给处理器,也不会响应中断。这就是为什么,总是看到,启动中断程序前都进行了中断标志位清零操作。
        该函数共两个参数:baseAddressmask
    参数
    baseAddress
    EUSCI_A_UART模块的基地址
    mask
    掩码位对应的中断源将会被关闭。掩码值可以是以下量的逻辑或:
    EUSCI_A_UART_RECEIVE_INTERRUPT                                       接收中断
    EUSCI_A_UART_TRANSMIT_INTERRUPT                                     发送中断
    EUSCI_A_UART_RECEIVE_ERRONEOUSCHAR_INTERRUPT 收到错误的字符中断使能
    EUSCI_A_UART_BREAKCHAR_INTERRUPT                   接收间隔字符中断使能
    EUSCI_A_UART_STARTBIT_INTERRUPT                         起始位接收中断启用
    EUSCI_A_UART_TRANSMIT_COMPLETE_INTERRUPT                 发送完成中断使
        该函数修改UCAxCTL1寄存器的UCAxIE位。
        返回值:无。
      uint8_t EUSCI_A_UART_getInterruptStatus (uint16_t baseAddress, uint8_t mask)
        获取当前UART中断状态。
        这将为UART模块返回基于其传递的标志的中断状态。
        该函数共两个参数:baseAddressmask
      参数
    baseAddress
    EUSCI_A_UART模块的基地址
    mask
    返回掩码的中断标志位状态。掩码值可以是以下量的逻辑或:
    EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG
    EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG
    EUSCI_A_UART_STARTBIT_INTERRUPT_FLAG
    EUSCI_A_UART_TRANSMIT_COMPLETE_INTERRUPT_FLAG
        该函数修改UCAxIFG寄存器。
        返回值
        下面量的逻辑或:
    EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG
    EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG
    EUSCI_A_UART_STARTBIT_INTERRUPT_FLAG
    EUSCI_A_UART_TRANSMIT_COMPLETE_INTERRUPT_FLAG
        指示掩码标志状态。
      uint32_t EUSCI_A_UART_getReceiveBufferAddress (uint16_t baseAddress)
        为DMA模块返回UARTRX缓冲器地址
        这可以结合使用DMA直接接收到的数据存储到内存。
      参数
    baseAddress
    EUSCI_A_UART模块的基地址
        返回值:RX缓冲器地址。
      uint32_t EUSCI_A_UART_getTransmitBufferAddress (uint16_t baseAddress)
        为DMA模块返回UARTTX缓冲器地址
        这可以结合使用DMA直接接收到的数据存储到内存。
      参数
    baseAddress
    EUSCI_A_UART模块的基地址
        返回值:TX缓冲器地址。
      bool EUSCI_A_UART_init ( uint16 t baseAddress, EUSCI A UART initParam ∗ param )
      先进的UART模块初始化程序。
      被写进clockPrescalar(前置分频器),firstModReg,secondModRgeoverSampling(过采样)的参数应该提前计算好再传递给初始化函数。
      注释:oversampling指的是在对模拟信号进行采样的时候,采样频率比被采样信号的最大频率成分的两倍要高,即满足奈奎斯特采样定理(fs>=fmax)。
      在成功初始化UART模块前,这个函数将完成初始化该模块,单UART模块仍然是关闭的,必须使用函数EUSCI_A_UART_enable()使能启动。对于计算clockPrescalar,firstModReg,secondModReg和overSampling请使用下面链接:
      根据网页提供的工具可以方便的计算出初始化用的参数。如下图所示。

      参数
    baseAddress
    EUSCI_A_UART模块的基地址
    mask
    param是初始化结构体的指针。
        该函数修改寄存器UCAxCTL0UCPEN,UCPAR,UCMSB,UC7BIT,UCSPB,UCMODExUCSYNC位。
        返回值 STATUS_SUCCESS STATUS_FAIL
        注释:如果初始化成功了,返回STATUS_SUCCESS;如果初始化写入失败了,返回STATUS_FAIL
      uint8 t EUSCI_A_UART_queryStatusFlags ( uint16 t baseAddress, uint8 t mask )
        获取当前UART状态标志。
        该函数返回UART模块作为参数传送的标志位的状态
        注释:多次提到传送标志位的概念,意思就是,该函数中作为参数传送过去的标志位对应的当前状态将会作为返回值返回。
      参数
    baseAddress
    EUSCI_A_UART模块的基地址
    mask
    是将被返回的中断标志位状态掩码。
    EUSCI_A_UART_LISTEN_ENABLE
    EUSCI_A_UART_FRAMING_ERROR
    EUSCI_A_UART_OVERRUN_ERROR
    EUSCI_A_UART_BREAK_DETECT
    EUSCI_A_UART_ADDRESS_RECEIVED
    EUSCI_A_UART_IDLELINE
    EUSCI_A_UART_BUSY
        该函数修改寄存器UCAxSTAT的位。
        返回值:下面量的逻辑或。
    • EUSCI_A_UART_LISTEN_ENABLE
    • EUSCI_A_UART_FRAMING_ERROR
    • EUSCI_A_UART_OVERRUN_ERROR
    • EUSCI_A_UART_BREAK_DETECT
    • EUSCI_A_UART_ADDRESS_RECEIVED
    • EUSCI_A_UART_IDLELINE
    • EUSCI_A_UART_BUSY
      uint8_t EUSCI_A_UART_receiveData ( uint16_t baseAddress )
        接收已经发送到UART模块的一个字节。该函数从UART接收数据寄存器读取一个字节数据。
      参数
    baseAddress
    EUSCI_A_UART模块的基地址
        该函数修改寄存器UCAxRXBUF
        返回值:返回从UART模块收到的字节,强制转换为uint8_t
        注释:函数的类型就是返回值的类型,函数内部返回值必须以函数类型返回。
      void EUSCI_A_UART_resetDormant ( uint16_t baseAddress )
        从休眠模式重启UART模块。不休眠,所有接收到字符就置位UCRXIFG
    参数
    baseAddress
    EUSCI_A_UART模块的基地址
        该函数修改寄存器UCAxCTL1UCDORM位。
        返回值:无
      void EUSCI_A_UART_selectDeglitchTime ( uint16 t baseAddress, uint16 t deglitchTime )
        设置抗尖峰脉冲时间。
      参数
    baseAddress
    EUSCI_A_UART模块的基地址
    deglitchTime
    抗尖峰脉冲时间可选的值有:
    EUSCI_A_UART_DEGLITCH_TIME_2ns
    EUSCI_A_UART_DEGLITCH_TIME_50ns
    EUSCI_A_UART_DEGLITCH_TIME_100ns
    EUSCI_A_UART_DEGLITCH_TIME_200ns
        返回值:无
      void EUSCI_A_UART_setDormant ( uint16_t baseAddress )
        设置UART在休眠模式。在空闲线(串口线路闲置状态)或UCRXIFG置位前。
        在UART自动波特率检测模式,只有断点和同步字段组合才可置位UCRXIFG(在这种模式下,触发中断的条件)。
        参数
    baseAddress
    EUSCI_A_UART模块的基地址
        该函数修改寄存器UCAxCTL1
        返回值:无
    void EUSCI_A_UART_transmitAddress ( uint16_t baseAddress, uint8_t transmitAddress )
        根据选择的多处理器模式,发送要被发送的标记为地址的下一个字节。
      参数
    baseAddress
    EUSCI_A_UART模块的基地址
    transmitAddress
    被发送的下一个字节
        该函数修改寄存器UCAxTXBUFUCAxCTL1
        返回值:无
      void EUSCI_A_UART_transmitBreak ( uint16_t baseAddress )
        传输中断(停止,暂停,间断)。
        传输中断(停止)作为下一个写入发送缓冲器。在UART的自动波特率检测模式下,
        EUSCI_A_UART_AUTOMATICBAUDRATE_SYNC(0x55) 必须被写进
        UCAxTXBUF来生成所需的中断/同步字段。否则,默认同步(0x00)必须写入传输缓冲区。另外确保模块为发送下一个数据做好准备。
    参数
    baseAddress
    EUSCI_A_UART模块的基地址
        该函数修改寄存器UCAxTXBUFUCAxcTL1
        返回值:无
      void EUSCI_A_UART_transmitData ( uint16_t baseAddress, uint8_t transmitData )
        从UART模块发送一个字节。
        该函数放置提供的数据在UART发送数据寄存器里,并开始发送。
      参数
    baseAddress
    EUSCI_A_UART模块的基地址
    transmitData
    UART模块将要被发送出去的数据
        该函数修改寄存器UCAxTXBUF
        返回:无。
  • 4.3  例程

    例程将展示怎样使用EUSCI_A_UART API 来初始化EUSCI_A_UART并开始发送字符。

    // 使用SMCLK频率为16384000Hz配置UART模块波特率为115200

    // 可以在以下网址计算器计算出配置参数:
    // http://software-dl.ti.com/msp430/msp430 public sw/mcu/msp430/MSP430BaudRateConverter/index.html
    EUSCI_A_UART_ initParam uartConfig = {
    EUSCI_A_UART_ CLOCKSOURCE SMCLK, // SMCLK Clock Source
    8, // BRDIV = 8
    14, // UCxBRF = 14
    34, // UCxBRS = 34
    EUSCI_A_UART_ NO PARITY, // No Parity
    EUSCI_A_UART_ MSB 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 Baudrate
    };
    WDT_hold(WDT_BASE);
    // 设置DCO使用内部电阻,DCO将被配置在16.384MHz. 

    CS_setupDCO(CS_INTERNAL RESISTOR);
    // SMCLK设置与DCO相同的速度。SMCLK = 16.384MHz
    CS_initClockSignal(CS_SMCLK, CS_CLOCK DIVIDER_1);
    // 设置P1.2P1.3管脚作为UART管脚。P1.4 管脚作为LED输出
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);
    GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN4);
    GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN4);
    // 配置和使能UART外设 

    EUSCI_A_UART_ init(EUSCI_A0_BASE, &uartConfig);
    EUSCI_A_UART_ enable(EUSCI_A0_BASE);
    EUSCI_A_UART_ enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_ RECEIVE_INTERRUPT);
    while(1) {
    EUSCI_A_UART_ transmitData(EUSCI_A0_BASE, TXData);
    //进入休眠并等待退出LPM
    __bis_SR_register(LPM0_bits | GIE);
    }

     

  • 4.4  详解

      UART主要是通过一个结构体来初始化的
      从eusci_a_uart.h我们可以看到该结构体为
    typedef struct EUSCI_A_UART_initParam
    {
    uint8_t selectClockSource;
    uint16_t clockPrescalar;
    uint8_t firstModReg;
    uint8_t secondModReg;
    uint8_t parity;
    uint16_t msborLsbFirst;
    uint16_t numberofStopBits;
    uint16_t uartMode;
    uint8_t overSampling;
    } EUSCI_A_UART_initParam;
      根据库函数头文件的介绍,第一个时钟源选择变量,一共有两个值可以选择。分别是使用SMCLKACLK作为UART时钟源
      第二个,第三个,第四个,我们可以不用管,直接利用网页的工具进行计算,如果想知道怎么手工计算,请查看技术手册。
      第五个parity是奇偶校验,一共三个选项,无奇偶校验、奇校验和偶校验。默认情况是无奇偶校验。
      第六个是msborLsbFirs,高位优先或低位优先,默认低位优先。
      第七个是numberofStopBits,停止位数量,可以选择1个停止位2个选择位。默认1个停止位。
      第八个是uartMode,共4个模式,默认是EUSCI_A_UART_MODE模式,还可以选择EUSCI_A_UART_IDLE_LINE_MULTI_PROCESSOR_MODE(空闲线多处理器模式)、 EUSCI_A_UART_ADDRESS_BIT_MULTI_PROCESSOR_MODE(地址位多处理器模式)和EUSCI_A_UART_AUTOMATIC_BAUDRATE_DETECTION_MODE(自动波特率检测模式)。
      第九个是overSampling,有两个值可以选择,分别用来指示使用过采样波特率发生器还是使用低频率波特率发生器。分别是EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION和EUSCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION。
      详情参见技术手册相关章节。并在本帖后回复讨论。
      关于本章节函数的参数变量的选择,详情见eusci_a_uart.h
  • 本章节的作业:
      根据例程,编写串口发送和接收程序,发送LED_ON字符串点亮接收MCULED,发送LED_OFF,关闭接收MCULED,发送LED_TEST字符串,返回当前的LED状态
  • 好详细啊,谢谢分享!

  • 21ic网友针对教程的学习讨论异常热烈,现将部分精彩问答及分享内容整理呈现:


    • 1、

    A提问:

    DCO旁路模式什么概念?

     

    B回复:

    DCO 全称是Digitally Controlled Oscillator(DCO),DCO一共有两种模式,内部部电阻模式(Internal Resistor Mode)和外部电阻模式(External Resistor Mode),通过 CSCTL0寄存器的DCOR位选择。注意旁路模式是通过CSCTL0寄存器的DCOBYP位置1选择的。通过datasheet了解到,外部电阻模式提供更高的时钟精度在绝对容度和温度漂移方面,原文为This mode offers higher clock accuracy in terms of absolute tolerance and temperature drift compared to internal resistor mode

    • 2

    2

    printf函数移植到UART程序中,很好用的
    #if 1
    #pragma import(__use_no_semihosting)                          
    struct __FILE 

            int handle; 
    }; 

    FILE __stdout;       
    _sys_exit(int x) 

            x = x; 

    int fputc(int ch, FILE *f)
    {         
            while((UCAxIFG&0X08)==0);//bit3 UCTXCPTIFG,传输完成标志
            UCAxTXBUF = (u8) ch;      
            return ch;
    }
    #endif

    • 3

    钟模块有四个系统时钟信号可以使用:

    ACLK:辅助时钟。当运行在DCO时,ACLK是固定在32kHz。如果设备是设置在DCO旁路模式,ACLK运行在旁路时钟频率的1/512
    MCLK:主时钟。MCLK可以被1,2,4,816分频。MCLK通常被CPU和系统使用。
    SMCLK:子系统主时钟。SMCLK可以被1,2,4,816分频。SMCLK可以被各个外围模块通过软件选择使用。
    SD24CLKSD24时钟提供一个1.024MHz固定频率的时钟给Sigma-Delta ADC(SD24)
      该时钟只为SD24的请求所使用。如果SD24功能必须在DCO旁路模式下工作,那么外部时钟频率必须是16.384Mhz

    430单片机时钟模块正是因为有这些时钟源配合不同的低功耗模式保证超低功耗。这个系列ACLK时钟32k的,记得G系列好像是12k的。去年做了一种产品因为功耗要求很低,5uA,使用三年,就是选用了G系列的MCUMCU大部分时间处于休眠状态LPM3,定时器工作在ACLK时钟下。。。

    • 4

    A提问:

    1、内部振荡器能不能屏蔽,外接有源晶振
    2、内置空闲线和地址位通信协议的多处理器系统,这个是怎么应用的,有没有案例分析下;这个支不支持串口接受空闲中断

     

    B回复:

    先回答第一个问题:可以根据需要选择使用内部振荡器或者外部晶振。

    第二个问题,我翻了翻手册,也没看到空闲中断,可能是没有这个中断。

    • 5

    A提问:

    可以使用内部晶振,也可以使用外部晶振。我觉得内部晶振可能不那么精确,应该和ST的芯片差不错内部晶振不精确;另外不同的时钟给不同的设备用,类似ST的模式。只是我看430f149外部晶振一般都是用4MH的,不知道是不是只能是4MHZ的?

     

    B回复:

    不是的,也可以选择其他频率

    • 6

    A提问:

    刚学430,不太懂,有个弱智的问题想问一下,如果不是MSP430i2系列的单片机,而是MSP430F6系列的,可不可以用库函数进行程序的编写?

    B回复:

    可以的,不过MSP430F6系列的库函数,和msp430i2xx系列的有一些差异。

    • 7

    A提问:

    看到例程上有这么一段程序:
    CS_initClockSignal(CS_MCLK, CS_CLKOCK_DIVIDER_8);
    CS_initClockSignal(CS_SMCLK, CS_CLKOCK_DIVIDER_2);
    我想问下,这个MCLKSMCLK一个8分频一个是2分频,他们在选择分频数值的时候是根据什么选择的?还有就是想问一下:8分频之后是不是比2分频之后的频率值小了?为什么MCLK的频率值要比SMCLK的频率值小呢?个人感觉应该要大一些才对……新手,可能问的幼稚了……

     

    B回复:

    MCLK:主时钟。MCLK可以被1,2,4,816分频。MCLK通常被CPU和系统使用。cpu执行指令的时钟。SMCLK:子系统主时钟。SMCLK可以被1,2,4,816分频。SMCLK可以被各个外围模块通过软件选择使用。例如定时器可以选择SMCLK时钟作为工作频率,定义一段时间。。。
    没有规定两者那个大。。

  • 8

    试着写了下发送和接收程序,接收在中断进行。
    uint8_t Rcvdat[10],SendDat[10]i, i=0;

    void EUSCI_A_UART_transmitData(EUSCI_A0_BASE,LED);

    if(EUSCI_A_UART_receiveData (EUSCI_A0_BASE)=="LED_ON")
    {
    LED = 0;
    }
    if(EUSCI_A_UART_receiveData (EUSCI_A0_BASE)=="LED_OFF")
    {
    LED =1;
    }

     

    B点评:

    每次只收一个字节的,我们可以这样,不是有停止位和启动位吗,先建立一个规则,把这个指令放到规则里,我们检测是否收到了一条完整的信息,在这条字符串找到关键词。然后判断。

  • 9

    //前面初始化和例程相同
    EUSCI_A_UART_ initParam uartConfig = {
    EUSCI_A_UART_ CLOCKSOURCE SMCLK, // SMCLK Clock Source
    8, // BRDIV = 8
    14, // UCxBRF = 14
    34, // UCxBRS = 34
    EUSCI_A_UART_ NO PARITY, // No Parity
    EUSCI_A_UART_ MSB 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 Baudrate
    };
    WDT_hold(WDT_BASE);
    // 设置DCO使用内部电阻,DCO将被配置在16.384MHz.
    CS_setupDCO(CS_INTERNAL RESISTOR);
    // SMCLK设置与DCO相同的速度。SMCLK = 16.384MHz
    CS_initClockSignal(CS_SMCLK, CS_CLOCK DIVIDER_1);
    // 设置P1.2P1.3管脚作为UART管脚。P1.4 管脚作为LED输出
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);
    GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN4);
    //GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN4);
    // 配置和使能UART外设
    EUSCI_A_UART_ init(EUSCI_A0_BASE, &uartConfig);
    EUSCI_A_UART_ enable(EUSCI_A0_BASE);
    EUSCI_A_UART_ enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_ RECEIVE_INTERRUPT);
    /////////////////////////////////////////////////////////
    //原谅我的渣渣C语言,LED默认低电平亮


    while(1) {
    if(EUSCI_A_UART_receiveData (EUSCI_A0_BASE)=="LED_OFF")
    {
            GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN4);
    }
    else if(EUSCI_A_UART_receiveData (EUSCI_A0_BASE)=="LED_ON")
    {
            GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN4);
    }
    else if(EUSCI_A_UART_receiveData (EUSCI_A0_BASE)=="LED_TEST")
    {
            GPIO_getInputPinValue (GPIO_PORT_P1, GPIO_PIN4);
            EUSCI_A_UART_ transmitData(EUSCI_A0_BASE, GPIO_getInputPinValue (GPIO_PORT_P1, GPIO_PIN4));
    }

    }

     

    • 10

    A提问:

    430的突出特点是低功耗,这两节都没有提如何达到低功耗的呢。。。

     

    B回复

    不同的低功耗模式lpm会关闭一些时钟或模块,合理的分配时钟模块,进入不同低功耗模式这样功耗会大大降低。从lpm0lpm4.5休眠条件下功耗越来越低的。如果定时器使用ACLK计时2秒,主循环lpm3休眠,2秒时间到退出休眠,住循环执行一次在休眠lpm3.这样cpu大部分时间都处于休眠状态,平均功耗大大降低。还有包括一些不用的io口可以设置为输出低电平,不用的模块都关闭。等等。。。。这些都是降低功耗的方法。

    • 11

    我看了一下那个单片机的技术手册,跟楼主的教程对比了一下,发现了一个问题,就是串口UART可选的时钟有多种,
    那个MSP430i2xxFamilyUser'sGuide.pdf231页的结构图上,写的是通UCSSELx寄存器可以选择,UCLK,ACLK,SMCLK,SMCLK,
    其中SMCLK出现两次,我觉得第四个,当寄存器位对应11时候应该是MCLK,可是我查看了头文件。如下
    #define UCSSEL__UCLK           (0x0000)       /* USCI 0 Clock Source: UCLK */
    #define UCSSEL__ACLK           (0x0040)       /* USCI 0 Clock Source: ACLK */
    #define UCSSEL__SMCLK          (0x0080)       /* USCI 0 Clock Source: SMCLK */
    没有找到串行收发器使用MCLK的证据,也就是只要这两位的,高一位是1,就是成立的, 可以记作1x.
    所以不用太纠结,这个直接用库函数操作就很OK了,经过查证那个手册也是没错的,只是没有写清楚。

     

    • 12

    我看大家都对空闲线多处理器协议那个不懂,我终于找到资料了,附上:

    空闲线多处理器模式

    在空闲线多处理器协议中(ADDRIDLE MODE位为0),数据块被各数据块间的空闲时间分开,该空闲时间比块中数据帧之间的空闲时间要长。一帧后的空闲时间(1O个或更多个高电平位)表明新块的开始,每位的时间可直接由波特率的值(bits)计算,空闲线多处理器通信格式如图1所示。
     
      图空闲线多处理器通信格式
      (1)空闲线模式操作步骤
      接收到块起始信号后,SCI被唤醒。
      处理器识别下一个SCI中断。
      中断服务子程序将接收到的地址与接收节点的地址进行比较。
      如果CPU的地址与接收到的地址相符,则中断服务子程序清除SLEEP位,并接收块中剩余的数据。
      如果CPU的地址与接收到的地址不符,则SLEEP位仍保持在置位状态,直到检测到下一个数据块的开始,否则CPU都不会被SCI端口中断,继续执行主程序。
      (2)块起始信号
      有两种方法发送块的开始信号。
      方法1:特意在前后两个数据块之间增加lO位或更多位的空闲时间。
      方法2:在写SCITXBUF寄存器之前,SCI口首先将TXWAKE位(SCICTL1,位3)置1。这样就会自动发送11位的空闲时间。在这种模式中,除非必要,否则串行通信线不会空闲。在设置TXWAKE后发送地址数据前,要向SCITXBUF写入一个无关的数据,以保障能够发送空闲时间。
      (3)唤醒暂时(WUT)标志
      与TXWAKE位相关的是唤醒暂时(WUT)标志位,这是一个内部标志,与TXWAKE构成双缓冲。当TXSHFSCITXBUF装载时,WUFTXWAKE装入,TXWAKE0。如图2所示。

    双缓冲的WUTTXSIIF
      (4)块的发送开始信号
      在块传送过程中需要采用下列步骤发送块开始信号:
      1TXWAKE位。
      为发送一个块开始信号,写一个数据字(内容不重要)到SCITXBUF寄存器。当块开始信号被发送时,写入的数据字被禁止,且在块开始信号发送后被忽略。当TXSHF(发送移位寄存器)再次空闲后,SCITXBUF寄存器的内容被移位到TXSHF寄存器,TXWAKE的值被移位到WUT中,然后TXWAKE被清除。由于TXWAKE1,在前一帧发送完停止位后,起始位、数据位和奇偶校验位被发送的11位空闲位取代。
      写一个新的地址值到SCITXBUF寄存器。
      在传送开始信号时,必须先将一个无关数据写入SCITXBUF寄存器,从而使TXWAKE位的值能被移位到WUT中。由于TXSHFWUT都是双级缓冲,在无关数据字被移位到TXSHF寄存器后,才能再次将数据写入SCITXBUF
    5)接收器操作
      接收器的操作和SLEEP位无关,然而在检测到一个地址帧之前,接收器并不对RXRDY位和错误状态位置位,也不申请接收中断。

     

    另外百度百科的地址线,就是讨论课程中的这个问题

    地址线
    地址线是用来传输地址信息用的。举个简单的例子:cpu在内存或硬盘里面寻找一个数据时,先通过地址线找到地址,然后再通过数据线将数据取出来。 如果有32.就可以访问232次方的空间,也就是4GB。在地址位多处理器协议中(ADDR/IDLE MODE位为1),最后一个数据位后有一个附加位,称之为地址位。数据块的第一个帧的地址位设置为1,其他帧的地址位设置为0。地址位多处理器模式的数据传输与数据块之间的空闲周期无关(参看图在SCICCR寄存器中的位3——ADDR/IDLE MODE位)。
    TXWAKE位的值被放置到地址位,在发送期间,当SCITXBUF寄存器和TXWAKE分别装载到TXSHF寄存器和WUT中时,TXWAKE0,且WUT的值为当前帧的地址位的值.因此,发送一个地址需要完成下列操作:
    ●TXWAKE位置1,写适当的地址值到SCITXBUF寄存器。当地址值被送到TXSHF寄存器又被移出时,地址位的值被作为1发送。这样串行总线上其他处理器就读取这个地址。
    ●TXSHFWUT加载后,向SCITXBUFTXWAKE写入值(由于TXSHFWUT是双缓冲的,它们能被立即写入)。
    ●TXWAKE位保持0,发送块中无地址的数据帧。
    图 地址位多处理器通信格式
    一般情况下,地址位格式应用于11个或更少字节的数据帧传输。这种格式在所有发送的数据字节中增加了一位(1代表地址帧,0代表数据帧);通常12个或更多字节的数据帧传输使用空闲线格式。
    1)地址字节
    发送节点(Talker)发送信息的第一个字节是一个地址字节,所有接收节点(Listener)都读取该地址字节。只有接收数据的地址字节同接收节点的地址字节相符时,才能中断接收节点。如果接收节点的地址和接收数据的地址不符,接收节点将不会被中断,等待接收下一个地址字节。
    2Sleep
    连接到串行总线上的所有处理器都将SCI SLEEP位置1SCICTL1的第二位),这样只有检测到地址字节后才会被中断。当处理器读到的数据块地址与用户应用软件设置的处理器地址相符时,用户程序必须清除SLEEP位,使SCI能够在接收到每个数据字节时产生一个中断。
    尽管当SLEEP位置1时接收器仍然工作,但它并不能将RXRDYRXINT或任何接收器错误状态位置1,只有在检测到地址位且接收的帧地址位是1时才能将这些位置1SCI本身并不能改变SLEEP位,必须由用户软件改变。
    3)识别地址位
    处理器根据所使用的多处理器模式(空闲线模式或地址位模式),采用不同的方式识别地址字节,例如:
    空闲线模式在地址字节前预留一个静态空间,该模式没有额外的地址/数据位。它在处理包含lO个以上字节的数据块传输方面比地址位模式效率高。空闲线模式一般用于非 多处理器的SCI通信。
    地址位模式在每个字节中加入一个附加位(也就是地址位)。由于这种模式数据块之间不需要等待,因此在处理小块数据时比空闲线模式效率更高。
    4)控制SCI TXRX的特性
    用户可以使用软仵通过ADDR/IDLE MODE位(SCICCR,位3)选择多处理器模式,两种模式都使用TXWAKESCICTL1,位3)、RXWAKESCIRXST,位1)和SLEEP标志位(SCICTL1,位2)控制SCI的发送器和接收器的特性。
    5)接收步骤
    在两种多处理器模式中,接收步骤如下:
    在接收地址块时,SCI端口唤醒并申请中断(必须使能SCICTL2RX/BK INT ENA位申请中断),读取地址块的第一帧,该帧包含目的处理器的地址。
    通过中断检查接收的地址启动软件例程,然后比较内存中存放的器件地址和接收到数据的地址字节。
    如果上述地址相吻合表明地址块与DSP的地址相符,则CPU清除SLEEP位并读取块中剩余的数据;否则,退出软件子程序并保持SLEEP置位,直到下一个地址块的开始才接收中断。

    • 13

    经过认真的学习课程和观察库函数以及例程文件,终于知道baseAddress是什么了。
    比如库函数中总是出现,例如
    [size=13.6842107772827px]void [size=13.6842107772827px]EUSCI_A_UART_disable[size=13.6842107772827px] (uint16_t baseAddress)
    这个很简单吧,我刚一看真不知道这个baseAddress是什么,后来看了后面的内容,原来只不过是个参变量,哎,脑子秀逗了,这个跟随便写个ABC,没什么区别。
    只不过所有的基地址都起了这个名字,对应不同的外设时候才有不同的常量名字。比如在UART模块对应的基地址是EUSCI_A0_BASE
    IIC里面对应的基地址是EUSCI_B0_BASE
    这下明白了。谢谢版主的教程。以后学习430看来更简单了。

    • 14、
    @Leeone      
        内置空闲线和地址位通信协议  说白了 其实就是单片机的串口通信的sm2位的功能,大家应该知道单片机sm2  用来 干啥的吧?
    在多机通信中 是用来 区分地址和数据的。
             好,下面再回来说明MSP430这个系列的增强型串口的 空闲线   地址位。其实是用两种不同的办法实现同一个功能。你选择用
    空闲线的办法可以,地址位的也可以。空闲线 大家可能觉得抽象 ,我就大概说:总线要空闲 莫非 就是拉高 ,因为多个设备串在一起
    的时候  ,起决定性的是低电平。不发数据的机,你必须保持高电平,因为都在一条线上,是线与的 关系,你一直低的话,就会堵死。
    大家都动不了,所以交通就会繁忙,闲不了。所以要空闲就要保持高电平。所以说 ,内置空闲线就是不用你处理这个空闲的功能(也
    就是手动置高电平,跑过软件模拟单总线的同学应该明白,比如说I2c)。
           再说回来,430的内置空闲线,当你选
    择这个模式的时候(通过寄存器配置),它的接收跟发送线,在发完数据之后 
    会自动将总线拉高置为空闲。拉多长时间这个不用你里,你只要在相应的寄存器里设置好标志就行了。
           下面具体对空闲模式举个例子来说明吧 ,这样好明白些。
            正常来说,我们大家用单片机的串口来说  一有数据来  就进入串口中断,然后就处理数据。如果是N多个机器在一条总线上工作,一个机器发送数据,所以的机器都会中断,这样子 会导致每个机器都会很忙。 但是 在空闲模式下,就不会出现这种情况。下面说下思路,大家跟着思路应该就明白,不明白再问吧。
           思路:假如N多台在一条总线上的机器。  
    第一步:  地址发送
    发送方:  机器A要发数据给另外一台机器B通信。那么机器A首先要发送的就是 机器B的地址,在发送地址之前,把UCTXADDR置为1,表示传送地址。这样的话,机器A把数据发出以后,就会自动将总线拉高 一段时间  就是手册里说的   不少于10个BITs的总线拉高时间。
    接收方: 机器B,判断到这个是自己的地址之后(当然其它机器也会在这个时候会中断一次,因为一开始大家肯定都是处于接收地址的状态),就会改变自己判断总线空闲时间长度,(其实就是转为准备接收数据的状态)。
    第二步:数据发送
    发送方: 机器A,在发完地址之后,就会发数据,但是在这个过程中,间隔拉高总线电平的时间  不能够超过10bitS (当然啦 ,这个不用你干,你就设置好相对应的标志位就好了),这样子的话,接收方才能区分出来,什么是数据,什么是地址。在发送数据的过程中,因为,总线的空闲时间少于10bitS 。其它的没有接收到自己地址的,还处于接收地址的状态,所以他们不会进入中断。这样就避免了总线上有数据的时候,CPu 频繁的中断。
    接收方:机器B,就会开始接收数据,直接到总线再次进入接收地址的状态。
         
    所以 ,总的来说 ,这里的内置空闲总线,不是说啥都不干,(串口的时钟会一直对总线采样的)。只是用来区分发送的是地址,还是数据的一种手段而已。所以就不会有@Leeone串口接受空闲中断 的这种说法。 串口 要中断 ,就只有接收到数据的时候,(或者更加严格的说 ,是接收到属于自己的东西时候才会中断)。
        对于另外一个 地址位通信 就更加好理解了,  就是通过在发送的数据中  多加一个位 来表示传送的是数据  还是地址,这个跟单片机中的SM2 位  基本一样了。接收,发送过程跟上面一样   只是大家设置的标志位不一样而已 。
  • 15、

    根据这个图,再看教程很清楚明了啊。

    从上图可以清除的看出来,那个说的DCO的三个模式void CS_setupDCO( uint8_t mode )
    使用参数所选模式配置 DCO。 如果选择旁路模式,则需要在 CLKIN 管脚接入外部数字时钟
    信号来作为所有的设备(CPU、外设等) 的时钟信号。 ACLK 频率是不可以被编程的, 且固定在
    旁路时钟频率除以 512。 使用外部吊足模式, 需要在 ROSC 管脚连接一个 20KΩ的电阻器。 与使
    用内部电阻相比, 使用外部电阻模式,在绝对误差和温度漂移上, 可以提供更高的时钟精度。 请
    根据你所选的设备型号对应的数据手册的详细情况来选择不同的模式。
    该函数只有一个参数: mode。
    mode: 该参数可以选择的量有 CS_INTERNAL_RESISTOR, CS_EXTERNAL_RESISTOR,
    CS_BYPASS_MODE。
    就是这个函数,图上给出了,对应的Rint,Rext,CLKIN,其中对DCOBYP置位时候选择CLKIN通道,就是传说中大家疑问的旁路模式,CS_BYPASS_MODE。

    [size=16.470588684082px]也就是说旁路模式就是通过DCOBYP将输入旁路到外部的CLKIN,那么当然就电路复杂了,需要外部时钟源设备,还有使用Rext,就是选择外部电阻模式,就需要在ROSC上安装个电阻。选择内部电阻就是默认使用DCO输出16.384MHz.如果需要使用其他频率,需要通过编程CSIRFCAL,CSIRTCAL这两个寄存器。一般不推荐。
    [size=16.470588684082px]另外如果使用外部电阻,则是使用20-kΩ 0.1% ±50-ppm/°C 
    这个规格的电阻,不过也是不推荐,毕竟内部有了电阻了,你再用外部的,不一定准确。同样,如果更改DCO发生频率,需要修改寄存器,不过库函数没有给出方法,那就是,不建议这样用。

    • 16、

    uint32_t CS_getMCLK(void);  uint32_t CS_getSMCLK(void); uint32_t CS_getACLK(void);这三个函数是获取当前的时钟频率。1.  文中写到此外,使用这个API前应该调用CS_setupDCO(),以便DCO被校准,这样计算才是精确的。  补充一下啊,获取这个API其实还要调用void CS_initClockSignal (uint8_t clockSource, uint8_t clockSourceDivider)函数配置MCLK,SMCLK分频系数,不然怎么获得时钟频率呢。 不过我们一般在MAIN函数开始就会先调用CS_setupDCO和CS_initClockSignal 这两个函数来初始化时钟了。    之后如果在调用uint32_t CS_getMCLK(void);  uint32_t CS_getSMCLK(void); uint32_t CS_getACLK(void);这几个函数应该就不用在用CS_setupDCO这个函数了吧。

    2.这三个函数都有说明: 当设备安装在DCO旁路模式下,它不能正常工作.   因为旁路模式使用的是外部晶振,MCU本身不知道晶振频率故当然也不能获取MCLK,ACLK频率了。


    3.虽但说这第三个函数 当设备安装在DCO旁路模式下,它不能正常工作。 但是也有可能因为不知道误调用了这几个函数,编译器也不会报错啊。
      但是头文件中看这个函数使用。
      //*****************************************************************************//
    //! \brief Get the current SMCLK frequency in Hz
    //!
    //! This API returns the current SMCLK frequency in Hz. It does not work when
    //! the device is setup in DCO bypass mode. Also, CS_setupDCO() should be
    //! called before this API so that the DCO has been calibrated and this
    //! calculation is accurate.
    //!
    //!
    //! \return Current SMCLK frequency in Hz, 0 when in bypass mode
    //
    //*****************************************************************************
    extern uint32_t CS_getSMCLK(void);
    注意红色部分,在bypass mode模式返回0.  那我们看源文件。

    uint32_t CS_getSMCLK(void) {
        uint8_t divider = (CSCTL1 & 0x70) >> 4;
        return(CS_DCO_FREQ >> divider);
    }
    如果使用bypass模式作为DCO时钟,在调用设置SMCLK分频CS_initClockSignal 如果调用CS_getSMCLK返回就是错误的频率。
    则返回的要源文件函数中也不会返回0,这里写的感觉有点问题,不知道个人理解的对不对。
    个人感觉可以这样写
    uint32_t CS_getSMCLK(void) {
        uint8_t divider = (CSCTL1 & 0x70) >> 4;
        if(in DCO bypass mode)
            return  0;
        else
            return(CS_DCO_FREQ >> divider);
    }  这样就对应cs。h头文件的说明了,哈哈。。

    • 17、

    A提问

    使用外部晶振更稳定。
    至于哪个省电,这个还真不知道。我猜使用DCO更省电 ...

     

    B回复:

    外部晶振更稳定,DCO是压控振荡器,和RC振荡器原理类似,受电压和温度的影响较大,而晶振是靠石英晶体谐振,与石英晶体本身的谐振频率有关,受外界温度电压的影响较小。
    DCO功耗更低,我使用外部晶振时LPM2的待机电流约为1.2mA, 使用DOC能达到50uA.

    • 18

    针对DCO利用外部电阻产生时钟模式下,可以通过ROSC管脚连接一个外部高精度电阻,如原文所示:When DCOR bit is set to 1 by the application, the DCO selects the external resistor mode for operation. It is recommended to connect a 20-kΩ 0.1% ±50-ppm/°C resistor at the ROSC pin of the device for operating in the external resistor mode. This mode offers higher clock accuracy in terms of absolute tolerance and temperature drift compared to internal resistor mode.
    但是文中并没有对于此高精度电阻的特性给以明确说明,是用金属膜电阻还是碳膜电阻。同时对于电阻的封装形式有没有一个规定。比如最小得多大的封装。等等。对于不同特性电阻(精度相同,温漂特性相同的条件下)连接下,所产生的时钟的区别有多大?

    • 19、

    闲着没事,就把课后题给写了一下,根据提供的例程改写。用的是STC单片机串口接收思维,贴出来请各位大神指正,新手,多多包涵
    #include <msp430.h> 


    volatile uint8_t T[7] = "LED_OFF";
    volatile uint8_t R[7] = "LED_ON";
    volatile uint8_t E[7] = "ERROR";
    volatile uint8_t Rec[10];
    volatile uint8_t flag=3;

    int main(void) {
        EUSCI_A_UART_initParam uartConfig = {
            EUSCI_A_UART_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
            8,                                       // BRDIV = 8
            14,                                      // UCxBRF = 14
            34,                                      // UCxBRS = 34
            EUSCI_A_UART_NO_PARITY,                  // No Parity
            EUSCI_A_UART_MSB_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 Baudrate
        };

        WDT_hold(WDT_BASE);

        // Setting the DCO to use the internal resistor. DCO will be at 16.384MHz
        CS_setupDCO(CS_INTERNAL_RESISTOR);

        // SMCLK should be same speed as DCO. SMCLK = 16.384MHz
        CS_initClockSignal(CS_SMCLK, CS_CLOCK_DIVIDER_1);

        // Settings P1.2 and P1.3 as UART pins. P1.4 as LED output
        GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
                                                   GPIO_PIN2 | GPIO_PIN3,
                                                   GPIO_PRIMARY_MODULE_FUNCTION);
        GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN4);
        GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN4);

        // Configure and enable the UART peripheral
        EUSCI_A_UART_init(EUSCI_A0_BASE, &uartConfig);
        EUSCI_A_UART_enable(EUSCI_A0_BASE);

        EUSCI_A_UART_enableInterrupt(EUSCI_A0_BASE,
                                     EUSCI_A_UART_RECEIVE_INTERRUPT);

        while(1)
        {
                uint8_t i;
                while(EUSCI_A_UART_receiveData(EUSCI_A0_BASE)!='') //读取接收到的信息,如果不为空,则开始接收
                                   
                        for(i=0;i<8;i++)
                                Rec[i]=EUSCI_A_UART_receiveData(EUSCI_A0_BASE); //将接收到的信息放到数组Rec中
                        if(Rec[5]=='N')                                     //判断接收到数组的第五位。因为LED_ON、LED_OFF与LED_TEST从第五位开始不同,如果为N,则为LED_ON
                        {
                                GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN4);
                                GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN4);
                                flag=0;                                                                                        //点亮LED的同时,置标志位flag=0;当flag=0时,说明是灯是开着的
                                
                        }
                        else if(Rec[5]=='F')                                                                //判断接收到数组的第五位。因为LED_ON、LED_OFF与LED_TEST从第五位开始不同,如果为F,则为LED_OFF
                        {
                                GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN4);
                                GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN4);
                                flag=1;                                                                                 //关闭LED的同时,将flag=1;说明此时为LED_OFF
                        }
                        else if(Rec[5]=='E')                                                                //判断接收到数组的第五位。因为LED_ON、LED_OFF与LED_TEST从第五位开始不同,如果为E,则为LED_TEST
                        {
                                if(flag==0)                                                                                //读取此时的标志位,若flag=0;则说明是LED_ON,然后将R【7】=LED_ON发送出去
                                {
                                        for(i=0;i<8;i++)
                                                EUSCI_A_UART_transmitData(EUSCI_A0_BASE, R[i]);
                                }
                                else if(flag==1)                                                                //读取此时的标志位,若flag=1;则说明是LED_OFF,然后将R【7】=LED_OFF发送出去
                                {
                                        for(i=0;i<8;i++)
                                                 EUSCI_A_UART_transmitData(EUSCI_A0_BASE, T[i]);
                                }
                                else                                                                                        //读取此时的标志位,若flag既不是0也不是1,;则发送ERROR
                                {
                                        for(i=0;i<8;i++)
                                                 EUSCI_A_UART_transmitData(EUSCI_A0_BASE, E[i]);
                                }        
                                        
                        }
                                

              __bis_SR_register(LPM0_bits | GIE);
        }
    }

    • 20

    A提问:

    我的板子上引出了P1.1~P1.4等多个外接IO,均上拉,用于外部中断输入。我只打开其中某个IO中断(比如P1.1),其他端口

    禁止中断,但是外部向P1.1发生中断时,其他端口(P1.2~P1.3)中断标志位有时候居然也会被置位,非常奇怪!

     

    B回复:

    检查复位是否正常,可以添加点亮LED灯的程序判断复位是否正常和程序是否运行

     

    A追问:

    LPM3唤醒
    for(;;)                            
        {      
            // Stop WDT
            WDTCTL = WDTPW + WDTHOLD;  
                  
            // Enter LPM3 w/interrupt 
            _BIS_SR(LPM3_bits + GIE);   
            
            // Start WDT
            WDTCTL = WDT_ARST_1000;  
          
            //SysLoopTask
            do_SysLoopTask();       
            
        }//for 

        并且程序中使用了1秒定时器。在外接Jtag下载器时,程序运行一切正常,每隔1秒从睡眠中醒来,并且也能够响应外部IO中断;

    但是,如果去掉下载器让板子单独运行,程序就睡眠而不被外部中断或者内部的定时器唤醒。

     

    B回复:

    for(;;)                            
        {      
              // Start WDT_timer
             WDTCTL = WDT_ARST_1000;  
                  
            // Enter LPM3 w/interrupt 
            _BIS_SR(LPM3_bits + GIE);   
            
          
            //SysLoopTask
            do_SysLoopTask();       
            
        }//for 
    IO复用看下!
    建议多看看TI的手册和范例!430很简单!

    • 21

    MSP430有三个时钟源,三个时钟信号批发商,N个时钟用户。

    1、时钟源

    (1)DCO时钟,芯片内部时钟,系统启动时默认的工作时钟,但是不够稳定,容易随着电压和温度变化,不过,还好,芯片一般自带FLL锁相环装置,能够在一定程度上调整偏差。4系列处理器默认工作频率1.048576MHz,其他的处理器800kHz左右。

    (2)LFXT1,外部低频时钟,一般接32768Hz的晶振,无需旁接电容(有内部电容,可以通过FLL_CTL0的XCAPxPF选择不同的电容值),相应的引脚为XTIN和XTOUT。如果非得让LFXT1工作在高频模式,那么需要将FLL_CTL0寄存器(地址0053)的XTS_FLL置位。

    例如: FLL_CTL0 |= XCAP10PF + XTS_FLL ; //LFXT1内接10PF的电容 + LFXT1工作在高频

    注:不同型号的芯片可以选择的电容值不同,具体查看芯片手册。

    (3)XT2,外部高频时钟,该时钟需要外接谐振电容,引脚为XT2IN、XT2OUT。工作频率为450K-8MHz之间,可选的电容值一般为2pF左右。

    注:无论是LFXT1还是XT2,晶振都要尽量靠近引脚,且用地线包围晶振信号线。

    2、时钟信号批发商

    时钟信号批发商把时钟源打包配置后,销售给各个时钟终端用户。

    具体方式为,通过配置SCFQCTL、SCFI0、SCFI1、FLL_CTL0、FLL_CTL1将各个时钟进行分频,然后提供给mcu以及外围模块,并提供周到服务,保证时钟工作稳定,如果不稳定,免费提供更换服务,如:当检测到LFXT1失效时,自动切换到DCO,不过一般来说发生退货的可能性不大,所以不必太多考虑。

    这三个批发商为ACKL、MCLK、SMCLK,分别称为辅助时钟、主时钟、sm时钟,别想歪了,SM是Sub Main 、Clock,不是………… :P 。

    (1)ACLK只能做LFXT1的代理,它将LFXT1进行1/2/4/8分频之后,提供给外围模块。不用的时候还可以关闭,但是该时钟不可以被单独关闭。ACLK一般用于低速外设。

    例如:MOV #OSCOFF, SR //关闭所有的晶振,一般关闭晶振osc的时候,必然同时关闭CPU,也就是低功耗6模式,但是关闭CPU,不一定关闭osc。

    (2)MCLK的货源可以是LFXT1、XT2、DCO三者之一,包装后的频率可以是1/2/4/8/off。由于该时钟可以被关闭,所以可以用来降低功耗。

    (3)SMCLK可以来自DCO和XT2,或者DCO和LFXT1,根据具体的芯片型号不同而有区别。SMCLK一般用于高速外设。

    例如:MOV #SMCLKOFF, &FLL_CTL1 //关闭smclk时钟

    MOV #XT2OFF + SELM0 + SELS + FLL_DIV_2, &FLL_CTL1

    //关闭XT2晶振,MCLK选择DCO,SMCLK选择XT2,ACLK被2分频(来自LFXT1)

    总结:系统每次启动后,默认使用DCO作为MCLK和SMCLK时钟来源,ACLK时钟来自LFXT1,这些配置可以在系统启动后在程序中修改。

    • 22、

    1、CPU运行在VLO时钟下:
    这是最慢的时钟,在约12千赫兹下运行。因此,我们将通过可视化的LED闪烁的红色慢慢地在约每3秒钟率。我们可以让时钟系统默认这种状态,设置专门来操作VLO。我们将不使用任何ALCK外设时钟在此实验室工作,但你应该认识到,ACLK来自VLO时钟。
    #include <msp430g2231.h>
    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;           // 关闭看门狗定时器
    P1DIR = 0x40;                          // P1.6 配置输出
    P1OUT = 0;                            // 关闭LED
    BCSCTL3 |= LFXT1S_2;                   // LFXT1 = VLO
    IFG1 &= ~OFIFG;                       // 清除OSCFault 标志
    __bis_SR_register(SCG1 + SCG0);          // 关闭 DCO
    BCSCTL2 |= SELM_3 + DIVM_3;           // MCLK = VLO/8
    while(1)
    {
    P1OUT = 0x40;                       // 开启LED
    _delay_cycles(100);
    P1OUT = 0;                          // 关闭 LED
    _delay_cycles(5000);
    }
    }
    2、CPU运行在晶振(32768Hz)时钟下:
    晶体频率为32768赫兹,约3倍的VLO。如果我们在前面的代码中使用晶振,指示灯应闪烁大约每秒一次。你知道为什么32768赫兹是一个标准?这是因为这个数字是2的15次方,因此很容易用简单的数字计数电路,以每秒一次获得率 ——手表和其他时间时基。认识到ACLK来自外部晶振时钟。
    #include <msp430g2231.h>
    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;        // 关闭看门狗定时器
    P1DIR = 0x41;                       // P1.0 和P1.6配置输出
    P1OUT = 0x01;                      // 开启P1.0
    BCSCTL3 |= LFXT1S_0;                // LFXT1 = 32768Hz 晶振
    while(IFG1 & OFIFG)
    {
    IFG1 &= ~OFIFG;                   // 清除 OSCFault 标志
    _delay_cycles(100000);             // 为可见的标志延时
    }
    P1OUT = 0;                      // 关闭P1
    __bis_SR_register(SCG1 + SCG0);     // 关闭 DCO
    BCSCTL2 |= SELM_3 + DIVM_3;      // MCLK = 32768/8
    while(1)
    {
    P1OUT = 0x40;                   // 开启 LED
    _delay_cycles(100);
    P1OUT = 0;                     / / 关闭LED
    _delay_cycles(5000);
    }
    }
    3、CPU运行在晶振(32768Hz)和DCO时钟下:
    最慢的频率,我们可以运行DCO约在1MHz(这也是默认速度)。因此,我们将开始切换MCLK到DCO下。在大多数系统中,你会希望ACLK上运行的VLO或32768赫兹晶振。由于ACLK在我们目前的代码是在晶体上运行,我们会打开DCO计算。
    #include <msp430g2231.h>
    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;            // 关闭看门狗定时器
    if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
    {
    while(1);                               // If cal const erased, 挂起
    }
    BCSCTL1 = CALBC1_1MHZ;                // Set range
    DCOCTL = CALDCO_1MHZ;                //设置DCO模式
    P1DIR = 0x41;                          // P1.0 和P1.6配置输出
    P1OUT = 0x01;                         // P1.0 开启
    BCSCTL3 |= LFXT1S_0;                   // LFXT1 = 32768Hz
    while(IFG1 & OFIFG)
    {
    IFG1 &= ~OFIFG;                       // 清除OSCFault 标志
    _delay_cycles(100000);                 // 为可见标志延时
    }
    P1OUT = 0;                           // P1.6 关闭
    // __bis_SR_register(SCG1 + SCG0);       // 关闭DCO
    BCSCTL2 |= SELM_0 + DIVM_3;          // MCLK = DCO
    while(1)
    {
    P1OUT = 0x40;                       // P1.6 开启
    _delay_cycles(100);
    P1OUT = 0;                         / / P1.6 关闭
    _delay_cycles(5000);
    }
    }
    4、CPU运行在DCO时钟下:
    最慢的频率,我们可以运行DCO约在1MHz(这也是默认速度)。因此,我们将开始切换MCLK到DCO下。在大多数系统中,你会希望在VLO或者是晶振下运行ACLK。由于ACLK在我们目前的代码是在VLO上运行,我们会打开DCO运行。
    #include <msp430g2231.h>
    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;                // 关闭看门狗定时器
    if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
    {
    while(1);                                   // If cal const erased,挂起
    }
    BCSCTL1 = CALBC1_1MHZ;                     // Set range
    DCOCTL = CALDCO_1MHZ;                     // 设置DCO模式
    P1DIR = 0x40;                               // P1.6 配置输出
    P1OUT = 0;                                 // P1关闭
    BCSCTL3 |= LFXT1S_2;                        // LFXT1 = VLO
    IFG1 &= ~OFIFG;                             // 清除 OSCFault 标志
    //__bis_SR_register(SCG1 + SCG0);              // 关闭DCO
    BCSCTL2 |= SELM_0 + DIVM_3;                 // MCLK = DCO/8
    while(1)
    {
    P1OUT = 0x40;                          // P1.6 关闭
    _delay_cycles(100);
    P1OUT = 0;                            // P1.6 开启
    _delay_cycles(5000);
    }
    }

    • 22、

    1、CPU运行在VLO时钟下:
    这是最慢的时钟,在约12千赫兹下运行。因此,我们将通过可视化的LED闪烁的红色慢慢地在约每3秒钟率。我们可以让时钟系统默认这种状态,设置专门来操作VLO。我们将不使用任何ALCK外设时钟在此实验室工作,但你应该认识到,ACLK来自VLO时钟。
    #include <msp430g2231.h>
    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;           // 关闭看门狗定时器
    P1DIR = 0x40;                          // P1.6 配置输出
    P1OUT = 0;                            // 关闭LED
    BCSCTL3 |= LFXT1S_2;                   // LFXT1 = VLO
    IFG1 &= ~OFIFG;                       // 清除OSCFault 标志
    __bis_SR_register(SCG1 + SCG0);          // 关闭 DCO
    BCSCTL2 |= SELM_3 + DIVM_3;           // MCLK = VLO/8
    while(1)
    {
    P1OUT = 0x40;                       // 开启LED
    _delay_cycles(100);
    P1OUT = 0;                          // 关闭 LED
    _delay_cycles(5000);
    }
    }
    2、CPU运行在晶振(32768Hz)时钟下:
    晶体频率为32768赫兹,约3倍的VLO。如果我们在前面的代码中使用晶振,指示灯应闪烁大约每秒一次。你知道为什么32768赫兹是一个标准?这是因为这个数字是2的15次方,因此很容易用简单的数字计数电路,以每秒一次获得率 ——手表和其他时间时基。认识到ACLK来自外部晶振时钟。
    #include <msp430g2231.h>
    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;        // 关闭看门狗定时器
    P1DIR = 0x41;                       // P1.0 和P1.6配置输出
    P1OUT = 0x01;                      // 开启P1.0
    BCSCTL3 |= LFXT1S_0;                // LFXT1 = 32768Hz 晶振
    while(IFG1 & OFIFG)
    {
    IFG1 &= ~OFIFG;                   // 清除 OSCFault 标志
    _delay_cycles(100000);             // 为可见的标志延时
    }
    P1OUT = 0;                      // 关闭P1
    __bis_SR_register(SCG1 + SCG0);     // 关闭 DCO
    BCSCTL2 |= SELM_3 + DIVM_3;      // MCLK = 32768/8
    while(1)
    {
    P1OUT = 0x40;                   // 开启 LED
    _delay_cycles(100);
    P1OUT = 0;                     / / 关闭LED
    _delay_cycles(5000);
    }
    }
    3、CPU运行在晶振(32768Hz)和DCO时钟下:
    最慢的频率,我们可以运行DCO约在1MHz(这也是默认速度)。因此,我们将开始切换MCLK到DCO下。在大多数系统中,你会希望ACLK上运行的VLO或32768赫兹晶振。由于ACLK在我们目前的代码是在晶体上运行,我们会打开DCO计算。
    #include <msp430g2231.h>
    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;            // 关闭看门狗定时器
    if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
    {
    while(1);                               // If cal const erased, 挂起
    }
    BCSCTL1 = CALBC1_1MHZ;                // Set range
    DCOCTL = CALDCO_1MHZ;                //设置DCO模式
    P1DIR = 0x41;                          // P1.0 和P1.6配置输出
    P1OUT = 0x01;                         // P1.0 开启
    BCSCTL3 |= LFXT1S_0;                   // LFXT1 = 32768Hz
    while(IFG1 & OFIFG)
    {
    IFG1 &= ~OFIFG;                       // 清除OSCFault 标志
    _delay_cycles(100000);                 // 为可见标志延时
    }
    P1OUT = 0;                           // P1.6 关闭
    // __bis_SR_register(SCG1 + SCG0);       // 关闭DCO
    BCSCTL2 |= SELM_0 + DIVM_3;          // MCLK = DCO
    while(1)
    {
    P1OUT = 0x40;                       // P1.6 开启
    _delay_cycles(100);
    P1OUT = 0;                         / / P1.6 关闭
    _delay_cycles(5000);
    }
    }
    4、CPU运行在DCO时钟下:
    最慢的频率,我们可以运行DCO约在1MHz(这也是默认速度)。因此,我们将开始切换MCLK到DCO下。在大多数系统中,你会希望在VLO或者是晶振下运行ACLK。由于ACLK在我们目前的代码是在VLO上运行,我们会打开DCO运行。
    #include <msp430g2231.h>
    void main(void)
    {
    WDTCTL = WDTPW + WDTHOLD;                // 关闭看门狗定时器
    if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
    {
    while(1);                                   // If cal const erased,挂起
    }
    BCSCTL1 = CALBC1_1MHZ;                     // Set range
    DCOCTL = CALDCO_1MHZ;                     // 设置DCO模式
    P1DIR = 0x40;                               // P1.6 配置输出
    P1OUT = 0;                                 // P1关闭
    BCSCTL3 |= LFXT1S_2;                        // LFXT1 = VLO
    IFG1 &= ~OFIFG;                             // 清除 OSCFault 标志
    //__bis_SR_register(SCG1 + SCG0);              // 关闭DCO
    BCSCTL2 |= SELM_0 + DIVM_3;                 // MCLK = DCO/8
    while(1)
    {
    P1OUT = 0x40;                          // P1.6 关闭
    _delay_cycles(100);
    P1OUT = 0;                            // P1.6 开启
    _delay_cycles(5000);
    }
    }

    • 23、

    MSP430的时钟周期(振荡周期)、机器周期、指令周期之间的关系

    时钟周期也称为振荡周期:定义为时钟脉冲的倒数(时钟周期就是直接供内部CPU使用的晶振的倒数,例如12M的晶振,它的时钟周期就是1/12us),是计算机中的最基本的、最小的时间单位。在一个时钟周期内,CPU仅完成一个最基本的动作。时钟脉冲是计算机的基本工作脉冲,控制着计算机的工作节奏。时钟频率越高,工作速度就越快。


    机器周期:在计算机中,常把一条指令的执行过程划分为若干个阶段,每一个阶段完成一项工作。每一项工作称为一个基本操作,完成一个基本操作所需要的时间称为机器周期。8051系列单片机的一个机器周期由6个S周期(状态周期)组成。一个S周期=2个时钟周期,所以8051单片机的一个机器周期=6个状态周期=12个时钟周期。


    指令周期:执行一条指令所需要的时间,一般由若干个机器周期组成。指令不同,所需的机器周期也不同。


    专用知识:


    在430中,一个时钟周期= MCLK晶振的倒数。如果MCLK是8M,则一个时钟周期为1/8us;


    一个机器周期 =一个时钟周期,即430每个动作都能完成一个基本操作;


    一个指令周期 = 1~6个机器周期,具体根据具体指令而定。


    另:指令长度,只是一个存储单位与时间没有必然关系。

    MSP430根据型号的不同最多可以选择使用3个振荡器。我们可以根据需要选择合适的振荡频率,并可以在不需要时随时关闭振荡器,以节省功耗。这3个振荡器分别为:

    (1)DCO 数控RC振荡器。它在芯片内部,不用时可以关闭。DCO的振荡频率会受周围环境温度和MSP430工作电压的影响,且同一型号的芯片所产生的频率也不相同。但DCO的调节功能可以改善它的性能,他的调节分为以下3步:a:选择BCSCTL1.RSELx确定时钟的标称频率;b:选择DCOCTL.DCOx在标称频率基础上分段粗调;c:选择DCOCTL.MODx的值进行细调。


    (2)LFXT1 接低频振荡器。典型为接32768HZ的时钟振荡器,此时振荡器不需要接负载电容。也可以接450KHZ~8MHZ的标准晶体振荡器,此时需要接负载电容。

    (3)XT2 接450KHZ~8MHZ的标准晶体振荡器。此时需要接负载电容,不用时可以关闭。

    低频振荡器主要用来降低能量消耗,如使用电池供电的系统,高频振荡器用来对事件做出快速反应或者供CPU进行大量运算。当然高端430还有锁频环(FLL)及FLL+等模块,但是初步不用考虑那么多。

    MSP430的3种时钟信号:MCLK系统主时钟;SMCLK系统子时钟;ACLK辅助时钟。

    (1)MCLK系统主时钟。除了CPU运算使用此时钟以外,外围模块也可以使用。MCLK可以选择任何一个振荡器所产生的时钟信号并进行1、2、4、8分频作为其信号源。

    (2)SMCLK系统子时钟。供外围模块使用。并在使用前可以通过各模块的寄存器实现分频。SMCLK可以选择任何一个振荡器所产生的时钟信号并进行1、2、4、8分频作为其信号源。

    (3)ACLK辅助时钟。供外围模块使用。并在使用前可以通过各模块的寄存器实现分频。但ACLK只能由LFXT1进行1、2、4、8分频作为信号源。

    PUC复位后,MCLK和SMCLK的信号源为DCO,DCO的振荡频率默认为800KHZ。ACLK的信号源为LFXT1。

    MSP430内部含有晶体振荡器失效监测电路,监测LFXT1(工作在高频模式)和XT2输出的时钟信号。当时钟信号丢失50us时,监测电路捕捉到振荡器失效。如果MCLK信号来自LFXT1或者XT2,那么MSP430自动把MCLK的信号切换为DCO,这样可以保证程序继续运行。但MSP430不对工作在低频模式的LFXT1进行监测。


    为了实现具体的时钟可以设置跟时钟相关的寄存器,在低端430中是DCOCTL、BCSCTL1和BCSCTL2三个寄存器。而对于高端的430,则要考虑SCFI0、SCFQCTL、FLL_CTL0、FLL_CTL1和BTCTL等几个寄存器。具体设置,参看DataSheet。



    单片机上电后,如果不对时钟系统进行设置,默认800 kHz的DCOCLK为MCLK和SMCLK的时钟源,LFXTl接32768 Hz晶体,工作在低频模式(XTS=O)作为ACLK的时钟源。CPU的指令周期由MCLK决定,所以默认的指令周期就是1/800 kHz="1".25μs。要得到lμs的指令周期需要调整DCO频率,即MCLK=1 MHz,只需进行如下设置:BCSCTLl=XT20FF+RSEL2;


    //关闭XT2振荡器,设定DCO频率为1 MHz

    • 24

    我认真学习了教程后,对CS系统有一个很好的认识。

    第一,关于时钟信号的来源,系统内部提供了DCO压控振荡器是第一个来源,第二个来源是CLKIN管脚的,使用第二个来源需要使用DCO的旁路模式,就是把DCO搞到一边去,旁路到一边去,没它什么事。
    第二,所谓的MCLK,ACLK,SMCLK,以及供给SD24的LK,这四个都是从时钟信号源接收信号后经过分频处理获得不同频率,用于不同目的的信号分频与分配系统。
    这些不能称为时钟源,只能叫做时钟信号源信号处理与分配器,这样更恰当,不好理解的请看时钟系统模块图。主贴已经给了那个手册的下载附件。
    以上两点就是我对教程中CS的认识,谢谢。我是认真思考后才来参与回复的

     

    • 25

    关于第4章节的串口通信部分,我说一下我的看法,关于通信肯定需要时钟信号进行同步,本系列单片机的时钟信号来源有3种,SMCLK,ACLK,UCLK。
    UCLK这个不仔细读教程和手册真不知道干啥的,手册说是,external eUSCI clock,也就是外部的eUSCI时钟。
    查看封装图,可知道P1.1/UCA0CLK/SMCLK/TMS              P1.0/UCA0STE/MCLK/TCK
    另外P1.3和P1.2分别是UART的TXD和RXD,也就是说,1.1和1.0具备输出SMCLK和输出MCLK的功能。
    UCA0CLK:eUSCI_A0 clock input/output (direction controlled by eUSCI)。这一点就解释了部分朋友对如何获取这些时钟信号输出的问题了,这需要参考对应具体型号的数据手册,不同型号内部资源是不同的。

    • 26

    首先本课程是介绍的MSP430i2xx系列,虽然都是2系列,跟以往F2xx,以及超值G2xx系列还是有很大的不同的,重要的一点时钟系统,就很不同,这个i2系列为了保证系统的安全可靠的工业级,去掉了容易因为外部原因造成的时钟系统失败,比如晶振的问题。等等。我看了看,楼主的教程根本没有提到晶振,也就是该单片机根本不需要晶振,因为i2xx把晶振的震荡系统去掉了。毕竟好多单片机启动失败一大部分原因是晶振坏了,比如我买的USB声卡没用多久就坏了,检测就是晶振坏了,还有U盘,如果连接电脑无法识别也是晶振坏了。所以i2xx为了保证工业品质,去掉了容易出错了地方,特别采用了强化的DCO,该DCO跟以往的G2xx的DCO也是不同的,该DCO具备两种电阻匹配模式,一个内置的,一个外置的,从前的好像没有外置的,所以也就没有区分,我看了G2的手册做了对比,这个真没有,所以该i2xx系列独到之处就在于此,以前的DCO只能采用内部的电阻配合DCO起振,由于电阻具有热变效应,也就是温度不同阻抗会发生变化,所以MCU工作肯定发热,会影响到内部的电阻阻值,所以提供的外置接口ROSC,即芯片的第11个PIN,而且是非共用的PIN,这说明系统设计师对该端口多么的看重。

  • 根据要求写了课后作业,分别是串口发送和接收代码。

    #define LED_OFF       0x00
    #define LED_ON        0x01
    #define LED_TEST    0x02

    uint8_t  LED_Status = 0x00;
    uint8_t  flag = 0x00;

    Void UARTTRANSMIT(void)
    {
    //发送LED_ON指令,点亮LED
    EUSCI_A_UART_ transmitData(EUSCI_A0_BASE, LED_ON);

    // 发送空指令,等待串口接收指令并操作
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");


    //发送LED_ON指令,点亮LED
    EUSCI_A_UART_ transmitData(EUSCI_A0_BASE, LED_OFF);

    // 发送空指令,等待串口接收指令并操作
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");


    //发送LED_ON指令,点亮LED
    EUSCI_A_UART_ transmitData(EUSCI_A0_BASE, LED_TEST);

    // 发送空指令,等待串口接收指令并操作
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");

    }

    Void UARTRECEIVE(void)
    {
    Uint8_t  ReceData = 0x00;

    //接收指令
    ReceData = uint8_t EUSCI_A_UART_receiveData ( EUSCI_A0_BASE);

    //判断接收值
    Switch (ReceData)
    {
    //接收值为0x00,关掉LED,置标志位为0
    Case 0x00:
    {
    GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN4);
    flag = 0;
    }break;

    //接收值为0x01,开启LED,置标志位为1
    Case 0x01:
    {
    GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN4);
    flag = 1;
    }break;

    //接收值为0x02,根据标志位来设置LED_Status的值
    Case 0x02:
    {
    If(flag==0)
    {
    LED_Status = 0x00;
    }
    Else
    {
    LED_Status = 0x01;
    }
    }break;
    Default:break;
    }
    }

    • 28、
    当 设置DCO使用内部电阻,DCO将被配置在16.384MHz时
    CS_setupDCO(CS_INTERNAL RESISTOR);


    设置不同的SMCLK频率配置UART模块波特率为115200
    会有多种不同的方式
    CS_initClockSignal(CS_SMCLK, CS_CLOCK DIVIDER_1);
    CS_initClockSignal(CS_SMCLK, CS_CLOCK DIVIDER_2);
    CS_initClockSignal(CS_SMCLK, CS_CLOCK DIVIDER_4);
    CS_initClockSignal(CS_SMCLK, CS_CLOCK DIVIDER_8);
    CS_initClockSignal(CS_SMCLK, CS_CLOCK DIVIDER_16);


    因而对应的不同的初始化配置
    EUSCI_A_UART_ initParam uartConfig = {
    EUSCI_A_UART_ CLOCKSOURCE SMCLK, // SMCLK Clock Source
    BRDIV
    UCxBRF,
    UCxBRS ,
    EUSCI_A_UART_ NO PARITY, // No Parity
    EUSCI_A_UART_ MSB 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 Baudrate
    };
    如下图所示的计算可方面设置
    BRDIV,UCxBRF,UCxBRS ,
     


     

    仔细考虑下,配置不同的外设时钟,时钟越低,功耗应该就相对越低了,所以从功耗的角度考虑选择低频应该好些
    但是由于需要配置115200 的高串行通信速率,时钟太低,配置后的波特率是否有误差还是一个问题,如果误差过大就会有误码的可能、
    所以应该还是需要从多个角度考虑下

    • 29

    A提问:

    看到例程上有这么一段程序:
    CS_initClockSignal(CS_MCLK, CS_CLKOCK_DIVIDER_8);
    CS_initClockSignal(CS_SMCLK, CS_CLKOCK_DIVIDER_2);
    我想问下,这个MCLK和SMCLK一个8分频一个是2分频,他们在选择分频数值的时候是根据什么选择的?还有就是想问一下:8分频之后是不是比2分频之后的频率值小了?为什么MCLK的频率值要比SMCLK的频率值小呢?个人感觉应该要大一些才对…

     

    B回复:

    void CS_setupDCO( uint8_t mode )
      使用参数所选模式配置DCO。如果选择旁路模式,则需要在CLKIN管脚接入外部数字时钟信号来作为所有的设备(CPU、外设等)的时钟信号。ACLK频率是不可以被编程的,且固定在旁路时钟频率除以512。使用外部吊足模式,需要在ROSC管脚连接一个20KΩ的电阻器。与使用内部电阻相比,使用外部电阻模式,在绝对误差和温度漂移上,可以提供更高的时钟精度。请根据你所选的设备型号对应的数据手册的详细情况来选择不同的模式。
      该函数只有一个参数:mode。
      mode:该参数可以选择的量有CS_INTERNAL_RESISTOR,CS_EXTERNAL_RESISTOR,CS_BYPASS_MODE。
      返回值:空。
      注释:DCO的配置可以使用内部电阻和外部电阻,还有一个就是旁路模式,旁路模式就是可以通过一个时钟输入管脚将外部时钟信号灌入系统。

    首先是要选择时钟源,比如  CS_setupDCO(CS_INTERNAL_RESISTOR); 也就是配置时钟的内部电阻模式
    DCO频率为16.384MHz.

    CS_initClockSignal(CS_MCLK, CS_CLKOCK_DIVIDER_8);
    表示将主系统的时钟配置为2.048MHZ

    CS_initClockSignal(CS_SMCLK, CS_CLKOCK_DIVIDER_2);
    表示将子系统的时钟配置为8.196MHZ

    所以肯定是子系统的时钟频率高了

    • 30

    A提问:

    看到例程上有这么一段程序:
    CS_initClockSignal(CS_MCLK, CS_CLKOCK_DIVIDER_8);
    CS_initClockSignal(CS_SMCLK, CS_CLKOCK_DIVIDER_2);
    我想问下,这个MCLK和SMCLK一个8分频一个是2分频,他们在选择分频数值的时候是根据什么选择的?还有就是想问一下:8分频之后是不是比2分频之后的频率值小了?为什么MCLK的频率值要比SMCLK的频率值小呢?个人感觉应该要大一些才对…

     

    B回复:

    void CS_setupDCO( uint8_t mode )
      使用参数所选模式配置DCO。如果选择旁路模式,则需要在CLKIN管脚接入外部数字时钟信号来作为所有的设备(CPU、外设等)的时钟信号。ACLK频率是不可以被编程的,且固定在旁路时钟频率除以512。使用外部吊足模式,需要在ROSC管脚连接一个20KΩ的电阻器。与使用内部电阻相比,使用外部电阻模式,在绝对误差和温度漂移上,可以提供更高的时钟精度。请根据你所选的设备型号对应的数据手册的详细情况来选择不同的模式。
      该函数只有一个参数:mode。
      mode:该参数可以选择的量有CS_INTERNAL_RESISTOR,CS_EXTERNAL_RESISTOR,CS_BYPASS_MODE。
      返回值:空。
      注释:DCO的配置可以使用内部电阻和外部电阻,还有一个就是旁路模式,旁路模式就是可以通过一个时钟输入管脚将外部时钟信号灌入系统。

    首先是要选择时钟源,比如  CS_setupDCO(CS_INTERNAL_RESISTOR); 也就是配置时钟的内部电阻模式
    DCO频率为16.384MHz.

    CS_initClockSignal(CS_MCLK, CS_CLKOCK_DIVIDER_8);
    表示将主系统的时钟配置为2.048MHZ

    CS_initClockSignal(CS_SMCLK, CS_CLKOCK_DIVIDER_2);
    表示将子系统的时钟配置为8.196MHZ

    所以肯定是子系统的时钟频率高了

     

    • 31

    发送LED_ON字符串点亮接收MCU的LED,发送LED_OFF,关闭接收MCU的LED,发送LED_TEST字符串,返回当前的LED状态。

    //引用的库

    #include "driverlib.h"

    //需要传输的字符和LED状态变量

    volatile uint8_t TXDataOne[8] = "LED_OFF";

    volatile uint8_t TXDataTwo[8] = "LED_ON";

    volatile uint8_t TXDataThree[8] = "LED_TEST";

    volatile uint8_t RXData[8];

    volatile uint8_t LEDState=0;

    //配置UART和设置LED相对应的IO口

    void Configuration()

    {

                //波特率为115200 使用的是SMCLK时钟为16.384MHz

                EUSCI_A_UART_initParam uartConfig = {

                    EUSCI_A_UART_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source

                    8,                                       // BRDIV = 8

                    14,                                      // UCxBRF = 14

                    34,                                      // UCxBRS = 34

                    EUSCI_A_UART_NO_PARITY,                  // No Parity

                    EUSCI_A_UART_MSB_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 Baudrate

                };

     

                // Setting the DCO to use the internal resistor. DCO will be at 16.384MHz

                CS_setupDCO(CS_INTERNAL_RESISTOR);

     

                // SMCLK should be same speed as DCO. SMCLK = 16.384MHz

                CS_initClockSignal(CS_SMCLK, CS_CLOCK_DIVIDER_1);

     

                // Settings P1.2 and P1.3 as UART pins. P1.4 as LED output

                //设置P1.2和P1.3作为UART引脚,P1.4位LED管脚

                GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,

                                                           GPIO_PIN2 | GPIO_PIN3,

                                                           GPIO_PRIMARY_MODULE_FUNCTION);

                GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN4);

                GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN4);

     

                //使能中断

                EUSCI_A_UART_init(EUSCI_A0_BASE, &uartConfig);

                EUSCI_A_UART_enable(EUSCI_A0_BASE);

     

                EUSCI_A_UART_enableInterrupt(EUSCI_A0_BASE,

                                             EUSCI_A_UART_RECEIVE_INTERRUPT);

    }

    int main(void) {

    WDT_hold(WDT_BASE);

        uint8_t i=0;

        Configuration();

        //发送字符

        while(1)

        {

                for(i=0;i<9;i++)

            EUSCI_A_UART_transmitData(EUSCI_A0_BASE, TXDataOne[i]);

            __delay_cycles(500000);

            for(i=0;i<9;i++)

            EUSCI_A_UART_transmitData(EUSCI_A0_BASE, TXDataTwo[i]);

            __delay_cycles(500000);

            for(i=0;i<9;i++)

            EUSCI_A_UART_transmitData(EUSCI_A0_BASE, TXDataThree[i]);

            __delay_cycles(500000);

        }

    }

     

    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)

    #pragma vector=USCI_A0_VECTOR

    __interrupt

    #elif defined(__GNUC__)

    __attribute__((interrupt(USCI_A0_VECTOR)))

    #endif

    void USCI_A0_ISR(void) {

             uint8_t i=0;

        switch(__even_in_range(UCA0IV, USCI_UART_UCTXCPTIFG))

        {

        case USCI_NONE: break;

        case USCI_UART_UCRXIFG:

                for(i=0;i<9;i++)

            RXData[i] = EUSCI_A_UART_receiveData(EUSCI_A0_BASE);

     

    //检查字符,如果接收到的,是LED_ON字符串点亮接收MCU的LED,是LED_OFF,关闭接收MCU的LED,是LED_TEST字符串返回当前的LED状态

            if(RXData == "LED_ON")

            {

                GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN4);

                LEDState=1;

            }

            else if(RXData == "LED_OFF")

                    {

                       GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN4);

                       LEDState=0;

                 }

            else if(RXData == "LED_TEST")

            {

                    EUSCI_A_UART_transmitData(EUSCI_A0_BASE, LEDState);

            }

            else break;

        case USCI_UART_UCTXIFG: break;

        case USCI_UART_UCSTTIFG: break;

        case USCI_UART_UCTXCPTIFG: break;

        default: break;

        }

    }