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.

[参考译文] CCS/MSP-EXP430F5529LP:UART 通过 SMCLK 计时问题

Guru**** 2587365 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/612803/ccs-msp-exp430f5529lp-uart-clocked-via-smclk-problem

器件型号:MSP-EXP430F5529LP
主题中讨论的其他器件:MSP430WARE

工具/软件:Code Composer Studio

您好!

我使用的是 myUART_5529示例、可在以下位置找到: http://processors.wiki.ti.com/index.php/MSP_UART

在我尝试更改系统时钟之前、它工作得很好。 SMCLK 的默认速度设置为8MHz。 时钟配置如下:

#include "initClocks.h"

//--------------------------------------------------
// myClock.c (对于 lab_04a_clock 项目)('F5529 Launchpad)
//
//此例程将 ACLK 设置为从 REFO 运行,然后将 MCLK 和 SMCLK 配置为
//从和高频率内部时钟源(DCO)运行。
//
//振荡器:
// DCO = 8MHz (默认为~1MHz)内部高频振荡器
// REFO = 32KHz 内部32KHz 基准振荡器
// MODOSC = 5MHz 内部5MHz 振荡
器// VLO =~10kHz 内部超低功耗、低频振荡
器// XT1 =-KHz (未配置)外部晶振输入
// XT2 =-MHz (未配置)外部晶振输入
//
参考时钟:
// FLL = REFO = 32KHz 内部参考时钟;用于在运行时校准 DCO

//内部时钟:
// ACLK = REFO = 32KHz
// SMCLK = DCO = 8MHz
// MCLK = DCO = 8MHz
// MODCLK = MODOSC = 5MHz (默认)
//---

//***** 定义
//VLO -~10KHz
//REFO - 32768Hz
//XT1 - LF:<50KHz
//XT1 - HF:最大4MHz
//XT2 - 4-40MHz
//DCO -最大100KHz
至 CPU // MODOSC - 5 MHz 或5 MHz/128、由闪存或 ADC

#define LF_crystel_frequency _in Hz 32768 // 32KHz
#define HF_crystal_frequency in_Hz 8000000 // 40MHz

#define MCLK_REGLED_FREQUENCY IN_kHz 8000 // 25MHz
#define MCLK_FLLREF_Ratio MCLK_REGLED_FREQUENCY IN_kHz /(UCS_REFOCLK_FREQUENCY / 1024)//比率= 250

#define XT_TIMEOUT 50000

//***** 全局变量
uint32_t myACLK = 0;
uint32_t mySMCLK = 0;
uint32_t myMCLK = 0;
uint8_t 返回值= 0;
bool b 返回 = STATUS_FAIL;


//***** initClocks (初始化
内联 void initClocks(void){


//将引脚连接到时钟晶振
GPIO_setPeripheralModuleFunctionInputPin (
GPIO_PORT_P5、
GPIO_PIN5 + // P5.5上的 XOUT
GPIO_PIN4 + // P5.4上的 XIN
GPIO_PIN3 + // P5.3上的 XT2OUT
GPIO_PIN2 // P5.2上的 XT2IN
);

////将 ACLK 和 MCLK 信号输出到各自的管脚-这使您可以
////使用逻辑分析仪观察它们(P1.0上的 ACLK、P2.2上的 SMCLK、P7.7上的 MCLK)
// GPIO_setAssPeripheralModuleFunctionOutputPin (
// GPIO_PORT_P1、
// GPIO_PIN0 // P1.0上的 ACLK (与跳线 JP8上的 LED1共享)
//);
// GPIO_setAssPeripheralModuleFunctionOutputPin (
// GPIO_PORT_P2、
// GPIO_PIN2 // P2.2上的 SMCLK (BoosterPack -右侧(J5)引脚2)
//);

//*********
//配置内核电压电平
//*********
//设置内核电压电平以处理25MHz 时钟速率
PMM_setVCore (PMM_CORE_LEVEL_3);


//*********
//配置振荡器
//*********
//设置 LaunchPad 上使用的 XT1/XT2晶振频率,然后连接
//时钟引脚、以便 driverlib 知道它们的速度(这些速度)
// DriverLib 时钟'get'和晶振启动函数所需)
UCS_setExternalClockSource (
lf_crystal_frequency in_Hz、 // XT1CLK 输入
Hf_crystal_frequency _in_Hz // XT2CLK 输入
);

//初始化 XT1晶体振荡器(在晶体出现问题时使用超时)
//-这需要将 P5.4和 P5.5引脚连接(并配置)为时钟输入引脚。
//-另一种方法是使用非超时功能,如果未配置 XT1,该功能将“挂起”;
// UCS_TurnOnXT1 (CS_XT1_DRIVE_0、UCS_XCAP_3);(实际上,我们使用了非超时函数来设置 XT2)
//-这里使用的"WithTimeout"函数将始终退出,即使 XT1未能初始化也是如此。
//必须检查以确保 XT1已正确初始化... 在实际应用中、您会这样做
//通常用更有用的错误处理函数替换 while (1)。
bReturn=UCS_TurnOnLFXT1WithTimeout (
UCS_XT1_DRIVE_0、
UCS_XCAP_3、
XT_TIMEOUT
);

if (bReturn == STATUS_FAIL)
{
while (1);
}

//初始化 XT2晶体振荡器而不超时。
//如果出现故障,代码会在此处挂起。
//对于超时而不是代码挂起,请使用 UCS_TurnOnXT2WithTimeout()。
UCS_TurnOnXT2 (UCS_XT2_DRIVE_24MHZ_32MHz);

//这是使用超时选项打开 XT2的示例。
// bReturn = UCS_TurnOnXT2WithTimeout (
// UCS XT2驱动器4MHz 8MHZ,
// XT2_TIMEOUT
// );
//
// if (bReturn == STATUS_FAIL)
//{
// while (1);
//}

//验证默认时钟设置是否符合预期
myACLK = UCS_getACLK ();
mySMCLK = UCS_getSMCLK ();
myMCLK = UCS_getMCLK ();


//*********
//配置时钟
//*********
//将 ACLK 设置为使用 REFO 作为振荡器源(32KHz)
UCS_initClockSignal (
UCS_ACLK、 //您正在配置的时钟
UCS_REFOCLK_SELECT、 //时钟源
UCS 时钟分频器1 //将时钟源除以这个值
);

//将 REFO 设置为 FLL 的振荡器参考时钟
UCS_initClockSignal (
UCS_FLLREF、 //您正在配置的时钟
UCS_REFOCLK_SELECT、 //时钟源
UCS 时钟分频器1 //将时钟源除以这个值
);

//将 MCLK 和 SMCLK 设置为使用 DCO/FLL 作为其振荡器源(8MHz)
//该函数执行许多操作:计算所需的 FLL 设置;配置 FLL 和 DCO、
//然后将 MCLK 和 SMCLK 设置为使用 DCO (具有 FLL 运行时校准)
UCS_initFLSettle (
MCLK_REVed_frequency in_kHz、 // MCLK 频率
MCLK_FLLREF_Ratio MCLK 和 FLL 基准时钟源之间的//比值
);

////可选实验步骤将 MCLK 设置为从 REFO 运行
////这将使 LED 在我们的 while{}循环中非常严重地闪烁
// UCS_initClockSignal (UCS_BASE、
// UCS_MCLK、 //您正在配置的时钟
// UCS_REFOCLK_SELECT、 //时钟源
// UCS 时钟分频器1 //将时钟源除以这个值
//);

//选择 XT2作为 SMCLK 源
//我们必须重新进行此调用... 为什么? 如果您使用 UCS_initFLSettle()到
//设置 MCLK,它还配置 SMCLK;因此,您应该调用它
设置 MCLK 后的//函数
/*UCS_initClockSignal (
UCS_SMCLK、
UCS_XT2CLK_SELECT、
UCS 时钟分频器1
);*

//验证修改后的时钟设置是否符合预期
myACLK = UCS_getACLK ();
mySMCLK = UCS_getSMCLK ();
myMCLK = UCS_getMCLK ();
}

如果我取消注释:

UCS_initClockSignal (
UCS_SMCLK、
UCS_XT2CLK_SELECT、
UCS 时钟分频器1
); 

然后 UART 打印垃圾。 我通过  UCS_getSMCLK()调用检查了 SMCLK,它将按预期返回8000000。 如果没有 UCS_initClockSignal(),SMCLK 返回8192000,UART 运行正常。

奇怪的是、如果我将 XT2晶振设置为在8192000 (与工作版本相同)下运行、它会打印垃圾。 我缺少什么?

谢谢!

P.S.下面是 myUART.c 函数:

//----------------------------------
// uart.c ('FR6989 Launchpad)
//---------------------------

//***** 首页文件
#include "myUart.h"
#include "string.h"

//***** 定义
//#define MYUART_IDLE 0
//#define MYUART_WRITE 1
//#define MYUART_ECHO 2

//***** 函数原型
//static unsigned char EOL (unsigned char);

//***** 全局变量

静态无符号短整型 txBufLen = 0; //剩余要输出的字节数;随着每个字符的发送而递减

。
// struct uart_t myUart;
//
//此结构定义了 USCI_A 端口的 UART 函数使用的资源。
// typedef 位于关联的头文件(myUart.h)中。 目标是尝试//
将各种端口设置封装到单个结构中,以便
//将此代码移植到新器件更容易。
//-某些字段由器件定义(基址、UART 通道数)。
//-其他由硬件板布局定义-在大多数情况
下、UART 实际上可以//分配到几个不同的端口/引脚位置。
//-最后、有许多"通道变量"用于指示
运行时端口的状态//。
///----------------------------------------------
struct uart_t myUart ={
通道数、 //器件上的 UART 数量
通道[0]={USCI_A0_BASE、 // USCI_A 端口的基地址
GPIO_PORT_P4、 // TX 引脚的 GPIO 端口设置
GPIO_PIN4、
null、 // F5229外设引脚配置没有多个 SEL 位
GPIO_PORT_P4、 // RX 引脚的 GPIO 端口设置
GPIO_PIN5、
null、 // F5229外设引脚配置没有多个 SEL 位
0、 //波特率
0、 //打开- UART 端口已打开并配置
1、 // TxBusy -
0、 // TxRDY
1、 // RxBusy
0、 // RxRDY
NOECHO // RxEcho
}、
通道[1]={USCI_A1_BASE、 // USCI_A 端口的基地址
GPIO_PORT_P3、 // TX 引脚的 GPIO 端口设置
GPIO_PIN4、
null、 // F5229外设引脚配置没有多个 SEL 位
GPIO_PORT_P3、 // RX 引脚的 GPIO 端口设置
GPIO_PIN5、
null、 // F5229外设引脚配置没有多个 SEL 位
0、 //波特率
0、 //打开- UART 端口已打开并配置
1、 // TxBusy -
0、 // TxRDY
1、 // RxBusy
0、 // RxRDY
DOECHO // RxEcho
}
};

//以下结构将 USCI_A 端口配置为从8MHz SMCLK 以9600波特运行
//波特率值计算在: software-dl.ti.com/.../index.html
USCI_A_UART_initParammyUart_Param_9600_8N1_SMCLK8MHz ={
USCI_A_UART_CLOCKSOURCE_SMCLK、
52、 //时钟预分频器
1、 // firstModReg
0、 //次级调制
USCI_A_UART_NO_奇 偶校验、
USCI_A_UART_LSB_FIRST、
USCI_A_UART_One_stop_bit、
USCI_A_UART_MODE、
USCI_A_UART_OPAMPLING_BAUDRATE_DEGEN
};

//以下结构将 USCI_A 端口配置为以8MHz SMCLK 的115200波特运行
//波特率值在 以下位置计算:software-dl.ti.com/.../index.html
USCI_A_UART_initParam myUart_Param_115200_8N1 SMCLK8MHz ={
USCI_A_UART_CLOCKSOURCE_SMCLK、
4、 //时钟预分频器
3、 // firstModReg
5、 //次级调制
USCI_A_UART_NO_奇 偶校验、
USCI_A_UART_LSB_FIRST、
USCI_A_UART_One_stop_bit、
USCI_A_UART_MODE、
USCI_A_UART_OPAMPLING_BAUDRATE_DEGEN
};

//以下结构将 USCI_A 端口配置为从32KHz ACLK 以9600波特运行
//波特率值在 以下位置计算:software-dl.ti.com/.../index.html
USCI_A_UART_initParam_9600_8N1_ACLK32Kz ={
USCI_A_UART_CLOCKSOURCE_ACLK、
3、 //时钟预分频器
0、 // firstModReg
3、 //次级调制
USCI_A_UART_NO_奇 偶校验、
USCI_A_UART_LSB_FIRST、
USCI_A_UART_One_stop_bit、
USCI_A_UART_MODE、
USCI_A_UART_LOW_FREQUENCY BAUDRATE_GEN
};

//*********
// myUart_init ()
//
初始化 USCI 外设的 UART 功能
//-"myUart_instance"参数允许用户设置任何 UART
//('FR6989上提供两个 UART)
//-此函数验证 DriverLib UART init 函



数是否返回//成功//-等待 UART 发送数据可通过"轮询"或//"中断"完成;此初始化例程启用 USCI UART 中断//*********
int myUart_init (uint16_t myUart_instance、uint32_t 波特率、USCI_A_uart_initParam * param)
{
//从 myUart 结构中获取该通道的 USCI 基址
uint16_t BaseAddr = myUart.channels[myUart_instance].BaseAddress;

//如果通道已初始化,则中止并返回错误
if (myUart.channels[myUart_instance].Open)
return (status_already _open);

//使用提供的两组参数之一初始化 UART (或修改以上参数以满足您的需求)
if (STATUS_FAIL == USCI_A_UART_init (BaseAddr,param))
return (status_init_failed);

//波特率保持以供将来的时钟调整函数使用
myUart.channels[myUart_instance].baudate =波特率;

//启用(即打开) UART
USCI_A_UART_ENABLE (BaseAddr);

//设置 UART 通道的此实例的状态标志
myUart.channels[myUart_instance]。Open = 1; //表示端口已打开并已初始化
myUart.channels[myUart_instance].txBusy = 0; //将 TX 端口设置为“非忙”(因为我们尚未主动发送数据)
myUart.channels[myUart_instance].RxBusy = 0; //将 RX 端口设置为“非忙”(因为我们尚未主动接收数据)
myUart.channels[myUart_instancy].TxRDY = 1; // TX 端口默认为就绪,因为发送缓冲区为空)
myUart.channels[myUart_instance].RxRDY = 0; //默认情况下,RX 端口尚未就绪,因为尚未读取任何内容

//返回成功,如果我们这么做
return (status_init_successful);
}


//*************
// myUart_writeBuf ()
//
////将 UART 配置为发送数据缓冲
区//- USCI_A_UART_transmitData () DriverLib 函数处理发送一
个//字节的数据,而此函数将发送整个缓冲区
//-这是一个'blocking'函数-即, 在
发送完整个//缓冲区之后才会退出;不过,此函数会等待
//使用 LPM0 (和发送中断)
//-如果 UART 不忙于发送数据,此函数会发送
//第一个字节的数据, 然后、让 UART ISR 发送其余数据
//
//参数
//- myUart_instance:让我们选择发送缓冲区的 UART;无错误
// 已完成检查、假设您已成功
// 已初始化 UART
//-*txBuf: 要写入 UART 端口的数据缓冲区;函数
// 检查缓冲区是否没有 NULL 地址
//- BufLen: 您希望发送多少个字节(您不必
//) 发送经过的整个缓冲区)。 如果值为
// 0被传递、函数将计算缓冲
区// 您的长度
//- doCrLf: 是否要发送回车和换行
// 数据缓冲区之后、会发生什么情况? (1是;0 N0)
//-返回: 此函数返回发送
的字符数//*************
int myUart_writeBuf (uint16_t myUart_instance、unsigned char * txBuf、uint16_t BufLen、int DoCrLf)
{
uint16_t BaseAddr = myUart.channels[myUart_instance].BaseAddress; //从 myUart 结构中获取该通道的 USCI 基址
unsigned char out = 0;
int ret =-1; //变量,用于保存此函数的返回值

//如果没有发送缓冲区,则退出
if (txBuf == NULL)
return (status_fail_NOBUFFER);

//如果我们已经忙于编写,则退出该函数,否则设置“忙”标志
if (myUart.channels[myUart_instance].txBusy)
return (STATUS_FAIL_BUSY);
其他
myUart.channels[myUart_instance].txBusy = 1;

//检查传输长度是否作为参数提供;如果为零、
//计算缓冲区的大小(即要传输的字符数)
if (BufLen =0)
txBufLen = strlen((const char *)txBuf );
其他
txBufLen = BufLen;

//根据用户的要求,添加回车(ENTER)和换行传送的传送长度
if ( DoCrLf )
{
txBufLen += 2;
}

//由于'txBufLen'在传输期间递减,因此保留原始值
RET = txBufLen;

//启用 USCI_Ax TX 中断
USCI_A_UART_enableInterrupt (BaseAddr、USCI_A_UART_Transmit _interrupt);

//继续发送字符直至完成
while (txBufLen >> 0)
{
if (myUart.channels[myUart_instance].txRDY ==1) //检查 TX 端口是否就绪(如果我们在这里,它应该已就绪)
{
myUart.channels[myUart_instancy].TxRDY = 0; //现在我们计划发送一个字节,清除就绪位

out =*txBuf; //从缓冲区中读取(请注意、如果我们正在执行 CRLF、这会读取超过缓冲区末尾的内容)
txBuf++; //将缓冲区指针移动到要发送的下一个项目

if ( DoCrLf ){ //如果执行 CRLF,请用 CR 或 LF 替换'OUT'
if (txBufLen == 2)
out = ASCII_linefeed;
否则(txBufLen ==1)
Out = ASCII_ENTER;
}

txBufLen--; //减少发送计数

USCI_A_UART_transmitData( BaseAddr,Out ); //将数据发送到发送端口
if (myUart.channels[myUart_instance].TxRDY ==0) //测试 TxRDY 以帮助防止在我们到达此步骤之前发生中断的竞态条件
_low_power_mode_0 (); //休眠 CPU,直到被发送就绪中断事件唤醒
} //(可以使用其他 LPMx 模式、具体取决于时钟要求)
}

//禁用 UART 发送中断
USCI_A_UART_DisableInterrupt (BaseAddr、USCI_A_UART_Transmit _interrupt);

//返回发送字符串的长度
返回(int) ret;
}


//*********
// myUart_readBuf ()
//
//此函数通过 UART 接收数据缓冲区。 这是一
个阻塞//函数、因此在接收到完整长度之前不会返回。
//
//参数:
//- myUart_instance:让我们选择哪个 UART 应该接收缓冲区;
// 不会进行错误检查、因为我们假定您
// 已成功初始化 UART
//-*rxBuf: 应将接收到的数据写入的缓冲区;
// 此函数检查缓冲区不能有//
空地址(如果是,则退出
//-*rxSize: 您希望接收多少个字节;默认大小
// 如果传递"0"、则使用1行(80字节);
// 请注意、接收回车或换行将
// 强制函数停止接收数据、即使
是// 尚未接收到字节的'length';
// 最后、我们使用了一个指针来表示大小、以便
// 返回实际接收到的字节数
//-返回: 功能的状态
//*********
int myUart_readBuf (uint16_t myUart_instance、unsigned char * rxBuf、uint16_t * rxSize)
{
uint16_t BaseAddr = myUart.channel[myUart_instance].BaseAddress; //检查 TX 端口是否就绪(如果我们在这里、它应该已就绪)
unsigned int ret = STATUS_INIT_Successful; //用于保持函数状态的变量(初始化为'scesse')
unsigned int i = 0; //在'for'循环中使用的局部变量
unsigned char in[3]={0、0、0}; //用于保存接收到的数据的临时变量(只有1个字节用于 recd 数据;用于添加 CRLF 的额外位置)
uint8_t inLen = 0; //当前"in"数组长度
uint16_t rxBufLen = 0; //输入缓冲器的当前长度

//如果没有读取缓冲区,则退出
if (rxBuf == NULL)
return (status_fail_NOBUFFER);

//如果我们已经忙于读取,则退出该函数,否则设置“忙”标志
if (myUart.channels[myUart_instance].RxBusy)
return (STATUS_FAIL_BUSY);
其他
myUart.channels[myUart_instance].RxBusy = 1;

//如果"0"作为"要读取的字节数"传递、则设置为默认大小
if (* rxSize =0)
*rxSize = DEFAULT_MAX_READ;

//如果启用了接收"回波"功能,请等待发送通道不忙
if (myUart.channels[myUart_instance].RxEcho){
if (myUart.channels[myUart_instance].txBusy ==1)
{
__LOW_POWER_MODE_0();
}
}

//清除和启用 USCI_Ax RX 中断
USCI_A_UART_clearInterrupt (BaseAddr、USCI_A_UART_receive_interrupt);
USCI_A_UART_enableInterrupt (BaseAddr、USCI_A_UART_receive_interrupt);

//继续传输,直到接收数据缓冲区到达指定的 rxSize
while ( rxBufLen <* rxSize )
{
//如果 RxRDY 始终高于'1'、我们可以"及时"读取数据
if (myUart.channels[myUart_instance].RxRDY >> 1)
RET = STATUS_RX_LOADD_REAR_TIME;

//如果尚未准备就绪,则在收到设置 RxRDY 标志的接收中断事件时休眠
if (myUart.channels[myUart_instance].RxRDY = 0){
__LOW_POWER_MODE_0();
}
否则{
myUart.channels[myUart_instance].RxRDY = 0; //如果 Rx 已就绪,请清除就绪位
IN[0]= USCI_A_UART_receiveData (BaseAddr); //从 RX 接收缓冲区读取字节
inLen = 1; //将'in"缓冲区长度设置为'1'字节

//如果输入字节是 cr (或换行),则将另一个字符添加到'in'
开关(IN[0])
{
ASCII_LINefeed 案例:
in[1]= ASCII_ENTER;
inLen++; //增加'IN'缓冲区长度的大小
*rxSize = rxBufLen; //将接收大小设置为当前缓冲区长度,以强制完成该函数
中断;

用例 ASCII_ENTER:
in[1]= ASCII_linefeed;
inLen++; //增加'IN'缓冲区长度的大小
*rxSize = rxBufLen; //将接收大小设置为当前缓冲区长度,以强制完成该函数
中断;
}

//将'in"字符复制到数据接收缓冲区
对于(i = 1;i <= inLen;i++){
*(rxBuf + rxBufLen)= in[I-1];
rxBufLen++;
}

//如果启用了“回显”,则将新接收到的字符传回给发件人(对于没有“本地回显”的终端)
if (myUart.channels[myUart_instance].RxEcho){
if (!myUart.channels[myUart_instancy].txBusy) //等待发送不忙,然后再发送字符
{
myUart_writeBuf (channel_1、(unsigned char *) in、inLen、NOCRLF);
}
}

}

//禁用 RX 中断并将端口设置为“非忙”
USCI_A_UART_DisableInterrupt (BaseAddr、USCI_A_UART_receive_interrupt);
myUart.channels[myUart_instance].RxBusy = 0;

//返回状态
返回( ret );
}//*************



// USCI_A0中断服务例程
//*********
#pragma vector = USCI_A0_VECTOR
__INTERRUPT void myUart0_ISR (void)
{
int CHAN = 0;

开关(__even_in_range (UCA0IV、USCI_UCTXIFG))
{
USCI_NONE 案例:
中断;

// UART 接收中断
USCI_UCRXIFG 案例:

myUart.channels[chan].RxRDY++; //中断告诉我们 UART RX 缓冲区已准备好读取
中断;

// UART 发送中断
USCI_UCTXIFG 案例:

myUart.channels[chan].TxRDY = 1; //中断告诉我们 UART TX 缓冲区可用于写入
if (txBufLen =0)
myUart.channels[chan].txBusy = 0; //如果已传输完整缓冲区,则将 Tx 设置为“非忙”
中断;
//
// 案例 USCI_UART_UCSTTIFG:
// __no_operation();
// 中断;
//
// 案例 USCI_UART_UCTXCPTIFG:
// __no_operation();
// 中断;
}

//退出低功耗模式:
//现在我们已经接收到一个字节-或者已经准备好发送了
//另一个字节-我们需要唤醒 CPU (因为我们的读取/写入
//例程在等待 UART 执行其操作时进入 LPM)
_low_power_mode_off_in_exit ();

}*/

//*********
// USCI_A1中断服务例程
//*********
#pragma vector = USCI_A1_vector
__interrupt void myUart1_ISR (void)
{
int CHAN = 1;

开关(__even_in_range (UCA1IV、USCI_UCTXIFG))
{
USCI_NONE 案例:
中断;

// UART 接收中断
USCI_UCRXIFG 案例:

myUart.channels[chan].RxRDY++; //中断告诉我们 UART RX 缓冲区已准备好读取
中断;

// UART 发送中断
USCI_UCTXIFG 案例:

myUart.channels[chan].TxRDY = 1; //中断告诉我们 UART TX 缓冲区可用于写入
if (txBufLen =0)
myUart.channels[chan].txBusy = 0; //如果已传输完整缓冲区,则将 Tx 设置为“非忙”
中断;
//
// 案例 USCI_UART_UCSTTIFG:
// __no_operation();
// 中断;
//
// 案例 USCI_UART_UCTXCPTIFG:
// __no_operation();
// 中断;
}

//退出低功耗模式:
//现在我们已经接收到一个字节-或者已经准备好发送了
//另一个字节-我们需要唤醒 CPU (因为我们的读取/写入
//例程在等待 UART 执行其操作时进入 LPM)
low_power_mode_off_in_exit();

}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Helder、
    您是否更改了 XT2? 否则、您将使用错误的值、因为它是一个4MHz 谐振器。 这可能会导致波特率发生变化、从而使 UART 输出显示为垃圾。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Cameron、

    是的、或者我认为是这样。 我使用了以下函数:

    UCS_setExternalClockSource (
    lf_crystal_frequency in_Hz、 // XT1CLK 输入
    Hf_crystal_frequency _in_Hz // XT2CLK 输入
    ); 

    其中 Hf_crystal_frequency _in_Hz 设置为80000。 此外,是否:

    UCS_initClockSignal (
    UCS_SMCLK、
    UCS_XT2CLK_SELECT、
    UCS 时钟分频器1
    );
    

    UCS_getSMCLK()将返回8MHz,从我理解的值返回当前设置为晶振的值。 但是、当我不初始化时钟信号(意味着 XT2CLK 与 CPU 一样)时、一切都正常。 在几个频率高达40MHz 的情况下尝试、它们都不起作用(根据此网页 http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html 设置预分频器和所需的设置)。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Helder、
    这是您必须进行物理更改的东西、例如、将新晶体焊接到位。 该函数返回寄存器内容、而不是晶体的测量频率。 我想、如果您观察到信号、它仍然是4MHz、或者根本不运行。 是否显示了任何 XT 故障标志?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Cameron、

    我不知道如何做到这一点。 它是以下条目之一?

    此外、从器件的用户指南中可以看到、XT2是一个4MHz 陶瓷谐振器。 那么、为了实现之前设置的8MHz (工作频率)、它使用的是 FLL? 那么、我的限值是25MHz 吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    故障标志记录在用户指南的第5.2.12节中。 参见 UCSCTL7。

    但是、您将如何处理8MHz 时钟? 您要尝试解决的实际问题是什么?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    实际上、我需要尽可能高的时钟、最初只有8MHz 时钟起作用。 我计划通过 UART 以115200或921600波特率与 Tiva123进行通信(使用"默认"示例进行管理)。 现在、我主要是为了了解有关 MSP 的更多信息、我对该平台非常陌生。

    我对技术讲座说可以在4MHz 到40MHz 之间计时感到困惑。 但是、我可能会更改晶体(可能使用数字振荡器信号)、也可能会使用 FLL 将时钟升高到~25MHz。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    如果您正在寻找快速传输、MSP430上的 UART 可以超过1Mbps。 我做了一些 基准测试

    对于设置、您可以使用我随附的计算器。

    e2e.ti.com/.../7585.MSP430UartCalc.rar

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    嗯、我不知道使用寄存器进行编程。 我有最基本的知识以这种方式进行编程。 但是、至少我已经设法使其在115200和4MHz 的 SMCLK (反向通道1)下正常工作!

    使用 XT2作为 FLL 基准将 SMCLK 上升到20MHz 并不是很有用、921600仍在打印垃圾。 但至少我有一个可用的波特率(115200)和更低的功耗。

    由于您已经证明 MSP430可以超过1Mbps、我想我将使用另一个 UART 模块或放弃反向通道...
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [报价用户="Helder Sales"]
    由于您已经证明 MSP430可以超过1Mbps、我想我将使用另一个 UART 模块或放弃反向通道...[/quot]

    如果我记得对、LP 反向通道限制为1Mbps。 此外、如果您需要在 MSP/PC 之间进行高速通信、则可以使用 USB CDC、该数据速率最高可达1MB/s

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    可能 MSP430Ware 或示例有其故障(即未优化)。 我正在考虑学习"传统"方法、这可能是解决方案。 感谢您的建议、我将了解一下这一点。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您是否仍然需要有关实施921600波特率的帮助、或者115200是否解决了这一问题?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Cameron、

    是的、我可以使用115200而不会出现任何问题、921600不是强制性的。 当我有时间时、我将了解如何正确地将 UART 设置为921600、现在我将重点介绍 MSP430Ware API 调用。

    顺便说一下、此 链接中提供的应用示例 (对于'F5529LP')有两个主要缺陷:

    在 myUart.c 中、在该部件上

    struct uart_t myUart ={
    通道数、 //器件上的 UART 数量
    通道[0]={USCI_A0_BASE、 // USCI_A 端口的基地址
    GPIO_PORT_P4、 // TX 引脚的 GPIO 端口设置
    GPIO_PIN4、
    null、 // F5229外设引脚配置没有多个 SEL 位
    GPIO_PORT_P4、 // RX 引脚的 GPIO 端口设置
    GPIO_PIN5、
    null、 // F5229外设引脚配置没有多个 SEL 位
    0、 //波特率
    0、 //打开- UART 端口已打开并配置
    1、 // TxBusy -
    0、 // TxRDY
    1、 // RxBusy
    0、 // RxRDY
    NOECHO // RxEcho
    }、
    通道[1]={USCI_A1_BASE、 // USCI_A 端口的基地址
    GPIO_PORT_P3、 // TX 引脚的 GPIO 端口设置
    GPIO_PIN4、
    null、 // F5229外设引脚配置没有多个 SEL 位
    GPIO_PORT_P3、 // RX 引脚的 GPIO 端口设置
    GPIO_PIN5、
    null、 // F5229外设引脚配置没有多个 SEL 位
    0、 //波特率
    0、 //打开- UART 端口已打开并配置
    1、 // TxBusy -
    0、 // TxRDY
    1、 // RxBusy
    0、 // RxRDY
    DOECHO // RxEcho
    }
    }; 

    这些引脚被分配到错误的通道(也是错误的引脚、即 P3.5)、当程序初始化所有 UART 引脚时、这不会立即出现问题、但是如果您尝试仅初始化其中一个 UART、这可能是一个问题。

    另一个问题是,当您通过  myUart_readBuf()读取缓冲区时,如果您设置了*rxsize 并在控制台上输入较小的内容(或通过 Rx 引脚),然后按“ENTER”(或发送“\r\n”),则您设置的 rxsize 将被接收到的字符串长度所取代。 不确定我是否清楚、因此我将举例说明:

    静态 uint8_t 大小= 0;//大小为0意味着函数将分配80
    
    UARTreadBuf 的默认值(channel_1、(unsigned char *) val、&size);//直到满或 CRLF 才返回
    
    //假设您键入"LED on"
    
    //使用字符串"LED on "
    
    UARTchar (unsigned char *)、readsize (unsigned char *);// //尝试输入"LED 关闭" 

    在此示例中, UARTreadBuf() 将在键入"LED off"之前返回。 因为键入"LED on"时,*rxsize 会将您分配给 size 的值替换为字符串"LED on"的长度,在本例中为6。 您只能键入"LED"。

    我解决此问题的方法是删除"*"运算符,使  myUart_readBuf (uint16_t myUart_instance、unsigned char * rxBuf、 uint16_t rxSize而不是  uint16_t * rxSize。 那么大小不会随接收缓冲区而变化。

    不确定在哪里提供有关这方面的反馈、但这些是我的发现。

    顺便说一下、感谢您的关注!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    谢谢 Helder、
    我将确保该反馈给相应的人。