本帖最后由 dirtwillfly 于 2017-7-2 22:55 编辑
转自http://www.deyisupport.com/quest ... /f/55/t/134679.aspx
本身从事硬件工作,最近心血来潮,用我手上的MSP-EXP430FR5969学习UART,接下来会发布SPI,I2C的文档。纯属分享学习经历,有什么错误请大家积极指出。参考文档的下载链接我一并给出,图片好像显示不出来,我把PDF版本一起放进来,直接导出来的,没有排版,大家别介意。
http://www.ti.com.cn/cn/lit/ds/zhcsch3e/zhcsch3e.pdf
http://www.ti.com.cn/cn/lit/ug/slau367n/slau367n.pdf
下面开始:
实例代码:
// MSP430FR59xx Demo - USCI_A0 External Loopback test [url=home.php?mod=space&uid=72445]@[/url] 115200 baud
//
// Description: This demo connects TX to RX of the MSP430 UART
// The example code shows proper initialization of registers
// and interrupts to receive and transmit data. If data is incorrect P1.0 LED is
// turned ON.
// ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = 1MHz
//
//
// MSP430FR5969
// -----------------
// RST -| P2.0/UCA0TXD|----|
// | | |
// -| | |
// | P2.1/UCA0RXD|----|
// | |
// | P1.0|---> LED
//
// P. Thanigai
// Texas Instruments Inc.
// August 2012
// Built with CCS V4 and IAR Embedded Workbench Version: 5.5
//******************************************************************************
#include <msp430.h>
volatile unsigned char RXData = 0;
volatile unsigned char TXData = 1;
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog
// Configure GPIO
P1OUT &= ~BIT0; // Clear P1.0 output latch
P1DIR |= BIT0; // For LED on P1.0
P2SEL1 |= BIT0 | BIT1; // USCI_A0 UART operation
P2SEL0 &= ~(BIT0 | BIT1);
// Disable the GPIO power-on default high-impedance mode to activate
// previously configured port settings
PM5CTL0 &= ~LOCKLPM5;
// Configure USCI_A0 for UART mode
UCA0CTLW0 = UCSWRST; // Put eUSCI in reset
UCA0CTL1 |= UCSSEL__SMCLK; // CLK = SMCLK
UCA0BR0 = 8; // 1000000/115200 = 8.68
UCA0MCTLW = 0xD600; // 1000000/115200 - INT(1000000/115200)=0.68
// UCBRSx value = 0xD6 (See UG)
UCA0BR1 = 0;
UCA0CTL1 &= ~UCSWRST; // release from reset
UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt
while (1)
{
while(!(UCA0IFG & UCTXIFG));
UCA0TXBUF = TXData++; // Load data onto buffer
}
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(UCA0IV,USCI_UART_UCTXCPTIFG))
{
case USCI_NONE: break;
case USCI_UART_UCRXIFG:
RXData = UCA0RXBUF; // Read buffer
if(RXData != TXData) // Check value
{
P1OUT |= BIT0; // If incorrect turn on P1.0
while(1); // Trap CPU
}
TXData++; // increment data byte
break;
case USCI_UART_UCTXIFG: break;
case USCI_UART_UCSTTIFG: break;
case USCI_UART_UCTXCPTIFG: break;
}
}
分析:
1、对于MSP430单片机,如果是要验证程序的话,首先需要关闭看门狗定时器,以保证正常调试。在产品量产后,可以不关闭看门狗来防止系统死机,但需要计算程序执行时间,进行喂狗操作。
通过以下代码关闭看门狗。
WDTCTL = WDTPW | WDTHOLD;
其中:WDTPW = 0x5A00, WDTHOLD = 0x0080. 写入密码并关闭看门狗。
2、配置GPIO口。
// Configure GPIO
P1OUT &= ~BIT0; // Clear P1.0 output latch
P1DIR |= BIT0; // For LED on P1.0
通过下面的文档说明可以知道如何配置:
12.2 Digital I/O Operation
The digital I/O are configured with user software. The setup and operation of the digital I/O are discussed
in the following sections.
12.2.1 Input Registers (PxIN)
Each bit in each PxIN register reflects the value of the input signal at the corresponding I/O pin when the
pin is configured as I/O function. These registers are read only.
• Bit = 0: Input is low
• Bit = 1: Input is high
NOTE: Writing to read-only registers PxIN
Writing to these read-only registers results in increased current consumption while the write
attempt is active.
12.2.2 Output Registers (PxOUT)
Each bit in each PxOUT register is the value to be output on the corresponding I/O pin when the pin is
configured as I/O function, output direction.
• Bit = 0: Output is low
• Bit = 1: Output is high
If the pin is configured as I/O function, input direction and the pullup or pulldown resistor are enabled; the
corresponding bit in the PxOUT register selects pullup or pulldown.
• Bit = 0: Pin is pulled down
• Bit = 1: Pin is pulled up
12.2.3 Direction Registers (PxDIR)
Each bit in each PxDIR register selects the direction of the corresponding I/O pin, regardless of the
selected function for the pin. PxDIR bits for I/O pins that are selected for other functions must be set as
required by the other function.
• Bit = 0: Port pin is switched to input direction
• Bit = 1: Port pin is switched to output direction
12.2.4 Pullup or Pulldown Resistor Enable Registers (PxREN)
Each bit in each PxREN register enables or disables the pullup or pulldown resistor of the corresponding
I/O pin. The corresponding bit in the PxOUT register selects if the pin contains a pullup or pulldown.
• Bit = 0: Pullup or pulldown resistor disabled
• Bit = 1: Pullup or pulldown resistor enabled
Table 12-1 summarizes the use of PxDIR, PxREN, and PxOUT for proper I/O configuration.
Table 12-1. I/O Configuration
3、设置引脚为外设模式。 P2SEL1 |= BIT0 | BIT1; // USCI_A0 UART operation
P2SEL0 &= ~(BIT0 | BIT1);
通过下面的文档说明可以知道如何配置:
因为PxSEL1和PxSEL0位不驻留在连续的地址中,所以不能同时更改这两个位。
4、解锁端口配置。
其中,LOCKLPM5 = 0x0001.可参考下面的文档说明
5、配置时钟。
这里没有配置时钟,为默认值:
// ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = 1MHz
如果需要配置时钟,可以参考下面的配置方法:
时钟系统操作
在PUC之后,CS模块默认配置为:
•选择LFXT作为LFXTCLK的振荡源。选择LFXTCLK为ACLK(SELAx = 0)的时钟源,ACLK不可分频(DIVAx = 0)。
•选择DCOCLK为MCLK和SMCLK(SELMx = SELSx = 3)时钟源,每个为8分频(DIVMx = DIVSx = 3)。
•LFXIN和LFXOUT引脚设置为通用I / O,并且LFXT保持禁用,直到I / O端口配置为LFXT工作模式。
•HFXIN和HFXOUT引脚设置为通用I / O,HFXT禁用。
如前所述,默认情况下选择LFXT,但LFXT被禁用。晶体管脚(LFXIN,LFXOUT)与通用I / O共用。要使能LFXT,必须设置与晶体管脚相关的PSEL位。当LFXTCLK使用32768-Hz晶体时,故障控制逻辑立即导致时钟源切换,ACLK由LFMODCLK提供,MCLK和SMCLK由MODCLK提供,因为LFXT没有立即稳定(见第3.2.8节)。
状态寄存器控制位(SCG0,SCG1,OSCOFF和CPUOFF)配置MSP430工作模式,并启用或禁用时钟系统模块的部分(请参见系统复位,中断和 操作模式章节)。通过CSCTL6注册CSCTL0,配置CS模块。
在程序执行期间,CS模块可以随时由软件进行配置或重新配置。 CS控制寄存器受密码保护,以防止无意中访问。
实例说明:配置 ACLK = 32768Hz, MCLK = SMCLK = BRCLK = default DCO = ~1MHz
首先,我们配置LFXIN和LFXOUT为LFXT工作模式。
PJSEL0 |= BIT4 | BIT5; // Configure XT1 pins
注意,之后需要解锁端口。
接下来,设置时钟:
(1)解锁时钟,CS控制寄存器受密码保护,以防止无意中访问。
CSCTL0_H = CSKEY >> 8; // Unlock CS registers
其中,CSKEY = 0xA500。
(2)设置DCO时钟源频率。需要DCORESL和DCOFSEL配合设置。
CSCTL1 = DCOFSEL_0; // Set DCO to 1MHz
其中,DCOFSEL_0 = 0x0000。
(3)设置各时钟的时钟源
CSCTL2 = SELA__LFXTCLK | SELS__DCOCLK | SELM__DCOCLK;
其中,SELA__LFXTCLK = 0x0000,SELS__DCOCLK = 0x0030,SELM__DCOCLK = 0x0003。
(4)设置分频参数
CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; // Set all dividers
其中,DIVA__1、DIVS__1、DIVM__1 都为0x0000。
(5)开启LFXT
CSCTL4 &= ~LFXTOFF; // Enable LFXT1
其中,LFXTOFF = 0x0001。
这里有一个需要注意里面一个名词LFXTBYPASS的理解,之前使用STM32时,里面有一个说明,可以参考下:
外部时钟源(HSE旁路)
在这个模式里,必须提供外部时钟。它的频率最高可达25MHz。用户可通过设置在时钟控制寄
存器中的HSEBYP和HSEON位来选择这一模式。外部时钟信号(50%占空比的方波、正弦波或
三角波)必须连到SOC_IN管脚,同时保证OSC_OUT管脚悬空。见图8。
外部晶体/陶瓷谐振器(HSE晶体)
4~16Mz外部振荡器可为系统提供更为精确的主时钟。相关的硬件配置可参考图8,进一步信息
可参考数据手册的电气特性部分。
在时钟控制寄存器RCC_CR中的HSERDY位用来指示高速外部振荡器是否稳定。在启动时,直
到这一位被硬件置’1’,时钟才被释放出来。如果在时钟中断寄存器RCC_CIR中允许产生中断,
将会产生相应中断。
HSE晶体可以通过设置时钟控制寄存器里RCC_CR中的HSEON位被启动和关闭。
(6)检测晶振是否正常
首先软件清除寄存器里对应的HFXT或者LFXT晶振错误标志。接着测试晶振是否正常。
do
{
CSCTL5 &= ~LFXTOFFG; // Clear XT1 fault flag
SFRIFG1 &= ~OFIFG;
}while (SFRIFG1&OFIFG); // Test oscillator fault flag
(7)晶振正常后所处时钟配置寄存器。
CSCTL0_H = 0; // Lock CS registers
6、配置USCI_A0为UART模式。
(1)在配置或者重新配置eUSCI_A 模块时应该先将UCSWRST置1以避免出现位置错误,配置完之后释放复位。
UCA0CTLW0 = UCSWRST; // Put eUSCI in reset
UCA0CTL1 &= ~UCSWRST; // release from reset
(2)设置eUSCI_A时钟源,作为波特率时钟源。
UCA0CTL1 |= UCSSEL__SMCLK; // CLK = SMCLK
选择SMCLK为时钟源。
(3)设置波特率。
首先计算波特率参数。
对于给定的BRCLK时钟源,使用的波特率决定了所需的分频因子N:
N = fBRCLK /波特率
分频因子N通常是非整数值,因此,使用至少一个分频器和一个调制器级来尽可能接近该因子。
如果N等于或大于16,TI建议通过设置UCOS16来使用过采样波特率生成模式。
注意:波特率设置快速设置
要计算波特率生成的正确设置,请执行以下步骤:
1.计算N = fBRCLK /波特率[如果N> 16继续步骤3,否则步骤2]
2. OS16 = 0,UCBRx = INT(N)[继续步骤4]
3. OS16 = 1,UCBRx = INT(N / 16),UCBRFx = INT([(N / 16) - INT(N / 16)]×16)
可以通过查看表24-4中的N(= N-INT(N))的小数部分来找到UCBRSx
5.如果选择OS16 = 0,TI建议执行详细的错误计算。
也可以直接查表Table 24-5确认波特率参数。
UCBRx = INT(N)
UCA0BR0 = 8; // 1000000/115200 = 8.68
因为N <16 ,所以OS16 = 0,UCBRFx 不需要写, 由8.68-8=0.68查Table 24-4得UCBRSx = 0xD6
UCA0MCTLW = 0xD600; // 1000000/115200 - INT(1000000/115200)=0.68
// UCBRSx value = 0xD6 (See UG)
UCA0BR1 = 0;
接下来使能中断
UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt
7、通过中断标志判断状态
while (1)
{
while(!(UCA0IFG & UCTXIFG));
UCA0TXBUF = TXData++; // Load data onto buffer
}
当发送完成后往发送buffer装载数据。
8、中断函数子程序。
可以参考下面的例程:
Example 24-1. UCAxIV Software Example
#pragma vector = USCI_A0_VECTOR __interrupt void USCI_A0_ISR(void) {
switch(__even_in_range(UCA0IV,18)) {
case 0x00: // Vector 0: No interrupts
break;
case 0x02: ... // Vector 2: UCRXIFG
break;
case 0x04: ... // Vector 4: UCTXIFG
break;
case 0x06: ... // Vector 6: UCSTTIFG
break;
case 0x08: ... // Vector 8: UCTXCPTIFG
break;
default: break;
}
}
其中,__even_in_range(UCA0IV,18)的解释:
使用__even_in_range 的好处是可以生成效率比较高的代码,在判断多中断源的中断的来源时可以使用此函数。
原型:unsigned short __even_in_range(unsigned short value, unsignedshort upper_limit);
功能:只能与switch 语句结合使用,判断value 是否为偶数且小于等于upper_limit。
|