主题中讨论的其他器件: BQ78350、 BQ76940、 MSP430G2553、 BQ76940EVM、 MSP430FR5994、 MSP430WARE、 MSP-EXP430FR5994、 MSP430F5338、 BQSTUDIO
TRM 负责电池管理的各个方面、包括配置/编程寄存器以启用/禁用某些功能。 但是、由于我只需要从微控制器连接 BMS 即可从 BQ78350-R1的配置值中获取/查询数据、因此是否需要进行一系列初始化或配置才能读取所需的值?
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.
TRM 负责电池管理的各个方面、包括配置/编程寄存器以启用/禁用某些功能。 但是、由于我只需要从微控制器连接 BMS 即可从 BQ78350-R1的配置值中获取/查询数据、因此是否需要进行一系列初始化或配置才能读取所需的值?
您好、Jan、
不幸的是、我无法披露整个代码。
简而言之、我们有一个状态机、它通过 SMBus 定期读取电池状态、然后对这些读数执行操作。
我可以共享位和段:
例如、要读取电池电压、您需要执行以下操作:
// 0x09对应于电池电压的寄存器地址 //第二个参数(0)对应于我们发送的命令的索引(用于回调) // batt_data_buffer 是存储数据的缓冲区 // battery_rx_done 是 SMBus 接口调用的回调函数,用于指示数据已被读取 smbus_requestWord (0x09、0、batt_data_buffer、batter_rx_done);
和读取操作状态(通过制造商访问命令完成):
// 0x0054参数对应于制造商访问中的命令 ID //第二个参数(1)对应于我们发送的命令的索引(用于回调) // batt 数据缓冲区是存储数据的缓冲区 // battery_rx_done 是 SMBus 接口调用的回调函数,用于指示数据已读取 smbus_requestMfrAccessReg (0x0054、1、batt 数据缓冲区、battery_rx_done);
SMBus 使用 BATTERY_Rx_DONE 回调函数来指示数据已接收。 它包含一个切换用例、然后将数据复制到适当的位置
void battery_rx_done (unsigned char id){ switch (id){ case 0://voltage 电压= batt 数据缓冲器[0]|(batt 数据缓冲器[1]<< 8); 中断; 案例1://操作状态 operation_status[0]= batt_data_buffer[6]; operation_status[1]= batt_data_buffer[5]; operation_status[2]= batt_data_buffer[4]; operation_status[3]= batt_data_buffer[3]; //检查是否存在永久性故障 if (operation_status[2]和0x10){ //检测到永久故障 Failure_Detected = 1; } 中断; … ...} }
您需要确定您将需要什么、在哪里以及如何使用您读取的数据。
此致、
米歇尔
您好、Terry 和 Michel。
我正在尝试使用 MSP430FR5994 (Launch Pad)实施一个非常简单的代码、以便通过 SMBus 读取 bq76940EVM 的电池电压。
我以电池充电器的 SLAA476A 示例和 Michel 提供的代码为基础。
不幸的是、我没有取得任何成功。 当我运行代码时、发送的唯一帧是下面显示的帧。
当我在代码中放置一些断点时,它 总是停留在 SMBus_NotReady()中,或者在中断的情况4中,当我注释它时。
我出了什么问题? 你有什么建议吗? 我应该在哪里查看?
代码:
smbus.h
#ifndef SMBus_H_ #define SMBus_H_ //通用定义 #define SMBus_MASTER_MODE_WRITE 0x00 #define SMBus_MASTER_MODE_ADDRE 0x01 #define SMBus_SLAVE_MODE_WRITE 0x02 #define SMBus_SLAVE_MODE_READ 0x03 #define SMBus_MODE_ADDR_ADDRE 0x09 #define PM_PACE_ADDRE #define 0x16 #define PM_FAIL_T=#define 000#define 000#define PM_FAIL #define 000#define SMBus_MODE_FLAG #define 000#define 000#define 000#define SMBus_ CRC8_Poly 0x07 #define CRC8_INIT_REM 0x0 // SMBus 数据声明 #define SMBus_DATA_TO_SLAVE 32 //发送表长度 #define SMBus_DATA_FIT_SLAVE 32 //接收表长度 // SMBus 命令定义 #define SBS_CMD_TEMP_TEMD_TEMP_VOLTAGE 0x09 #define SBS_CURRENT_0X0CCS_CURRENT #define CCS_CMD_CURRENT#define 0_CMD_CURRENT#define 0x14 #define SBS 0x16 #define SBS_CMD_Design_VOLTAGE 0x19 #define SBS_CMD_FTORY_NAME 0x20 #define SBS_CMD_DEVICE_NAME 0x21 #define SBS_CMD_CELL_VOLTAGE_4 0x3C #define SBS_CMD_CELL_VOLTAGE_3 0x3D #define SBS_CMD_COLL_STATEART_BYTCG #define 电池充电寄存器0x3E #define SBS #define COUNT_STATEARTTER/SBS COUNT_STATEART/ COYTC_BATERTTER1 SBS_REG_BATTERYSTATUS_FC BIT5 //完全充电 #define BUS_1 1 #define BUS_1 2 #define SMBus_MASTER_MODE 0 #define SMBus_SLAVE_MODE 1 #define SMBus_START_FLAG_SET 1 #define SMBus_START_FLAG_RESET 0 //外部全局变量声明 extern SMBus_Data_SLAVE_TXCH_DATA_SLAVE_SET 1 #define SMBus_SLAVE_ST_SLAVE_RT_SLAVE_RT_DATA_SET 1 #define 0 //从 SMBus_SLAVE_TXCH_SLAVE_OBJART/SLAVE_TXQ_SLAVE_RT_DATA_SLAVE_OBJART/无 符号 extern unsigned char * pRXData;//指向 RX 数据的指针 extern unsigned char RXByteCounter; extern unsigned char RXFlag;//数据接收标志 extern unsigned char TXFlag;//数据传输标志 extern unsigned char RWFlag;//读取/写入标志 extern unsigned char SMBus_Start_Flag; extern unsigned char size_bytes;extern unsigned char size_bytes; //函数原型 unsigned char SMBUS_NotReady(); 静态 unsigned short crc8MakeBitwise (unsigned char CRC、unsigned char Poly、unsigned char *Pmsg、unsigned int Msg_size); #endif /*SMBus_H_*/
main.c
#include #include //全局变量 unsigned char SMBus_Data_to_Slave[SMBus_data_to_Slave]; unsigned char SMBus_Data_fin_Slave[SMBus_data_fin_slave]; unsigned char * pTXData = 0x0; //指向 TX 数据的指针 unsigned char TXByteCounter = 0; unsigned char * pRXData = 0x0; //指向 RX 数据的指针 unsigned char RXByteCounter = 0; unsigned char RXFlag = flag_FAIL; //数据接收标志 unsigned char TXFlag = FLAG_FAIL; //数据传输标志 unsigned char RWFlag = SMBus_master_mode_read; //读取/写入标志 无符号 char SMBus_Start_Flag = SMBus_start_FLAG;//是否已启动事务? unsigned char smbus_access_status = 0x0; unsigned char crc_msg_size = 0; unsigned char crc_master_generated = 0; unsigned char crc_slave_generated = 0; unsigned char size_in_bytes; unsigned char smbus_command; static short crc8Makebwise char msg (char char cCRC、Bitg、unsigned pig、unsigned pig unsigned int i、j、carry; unsigned char msg; CRC =* Pmsg++; //加载到"crc"中的第一个字节 for (i = 0;i < Msg_size-1;I ++) { MSG =* Pmsg++; //在"msg"中加载下一个字节 for (j = 0;j < 8;j++) { 进位= CRC 和0x80; //检查 MSB=1 CRC =(CRC << 1)|(msg >> 7);//将下一个字节的1位移入 CRC if (carry) CRC ^= Poly; //如果 MSB=1,执行 XOR MSG <<= 1; //左移 msg 字节1 } } //前一个循环计算输入位流的 CRC。 为此、 //填充8个尾随零,结果值的 CRC 为 //已计算。 这给出了输入位流的最终 CRC。 for (j = 0;j < 8;j++) { 进位= CRC 和0x80; CRC <<= 1; if (carry) CRC ^= Poly; } return (CRC); } unsigned char SMBus_NotReady() { return ((UCB1STATW 和 UCBBUSY)||(UCB1STATW 和 UCSCLLOW)); } int main (void) { WDTCTL = WDTPW | WDTHOLD; //停止 WDT //禁用 GPIO 上电默认高阻抗模式以激活 //先前配置的端口设置 PM5CTL0 &=~LOCKLPM5; //时钟设置 CSCTL0_H = CSKKEY_H; //解锁 CS 寄存器 CSCTL1 = DCOFSEL_0; //将 DCO 设置为 x MHz CSCTL2 = SELA_VLOCLK | SELESS__DCOCLK | SELM_DCOCLK;//设置 SMCLK = M0CLK = DCO、ACLK = VLOCLK CSCTL3 = DIVA__1 | DIVM_1 | DIVM__1;//设置分频器 CSCTL2 = SELA_VLOCLK | SELESS__DCOCLK | SELM_DCOCLK;//设置 SMCLK = M0CLK = DCO、ACLK = VLOCLK CSCTL0_H = 0; //锁定 CS 寄存器 //将 UCB 设置为 I2C 模式 P5SEL0 |= BIT0 | BIT1; P5SEL1 &=~(BIT0 | BIT1); UCB1CTLW0 = UCSWRST; //将 eUSCI_B 置于复位状态 UCB1CTLW0 |= UCMODE_3 | UCMST | UCSSEL_SMCLK; // I2C 主控模式、SMCLK UCB1BRW = 0x0A; //波特率= SMCLK/UCBxBRW (十六进制) UCB1CTLW0 &=~UCSWRST; //清除复位寄存器 UCB1IFG &= 0xFF; //清除所有标志 UCB1I2CSA = BQ78350_ADDR; //从机地址是有效载荷的第一个字节 UCB1CTLW1 &=~UCSWRST; //清除 SW 复位,恢复操作 UCB1IE |= UCTXIE0 | UCNACKIE | UCRXIE; //发送和 NACK 中断使能 _enable_interrupt (); while (1) { while (SMBus_NotReady()); //等待 SMBus 变为空闲状态 SMBus_COMMAND = SBS_CMD_VOLTAGE; size_in_bytes = 2; TXByteCounter = 1; //目前 SMBus 命令的 TX 1字节 pTXData =&(smbus_command); //根据 SBS 命令规范接收字节数 //为 PEC 加一个额外的字节 RXByteCounter = size_in_bytes + 1; //将 RX 字节存储在全局数组中 pRXData =(unsigned char*) SMBus_Data_fin_Slave; //初始化标志以失败,除非成功 RXFlag = FLAG_FAIL; RWFlag = SMBus_MASTER_MODE_READ; //读取模式 while (UCB1CTL1 & UCTXSTP); //是否发送停止条件? TA1CTL = TASSEL_ACLK + TACLR + MC_UP; //开始计时器 A 测量超时 SMBus_Start_Flag = SMBus_start_FLAG_set; UCB1CTL1 |= UCTR + UCTXSTT; //开始! while (UCB1CTL1 & UCTXSTT); //确保发送起始条件 //从设备是否确认了自己的地址? 如果是、则继续 //使用命令和数据包。 if ((RXFlag!= FLAG_NACK)&&(RXFlag!= FLAG_FAIL)){ _bis_SR_register (LPM0_bits + GIE); //输入带中断的 LPM0 } // PEC 字节处理 CRC_msg[0]= SMBus_SLAVE_ADDRESS << 1; // R/W 位为低电平的从器件地址 crc_msg[1]= smbus_command; //命令字节 CRC_msg[2]=(SMBus_SLAVE_ADDRESS << 1)+ 1;//从地址、R/W 位为高电平 CRC_msg[3]= SMBus_Data_From_Slave[0]; //第一个字节 RX CRC_msg[4]= SMBus_Data_From_Slave[1]; //第二个字节 RX CRC_SLAVE_Generated = SMBus_Data_From_Slave[2];//存储从器件的 PEC 字节 CRC_msg_SIZE = 5; //字节数 /* CRC 函数调用,生成 CRC 字节与从器件 CRC*/进行比较 crc_master_generated = crc8MakeBitwise (CRC8_INIT_REM、CRC8_Poly、CRC_msg、CRC_msg_size); // PEC 字节验证 if (crc_master_generated = crc_slave_generated) {smbus_access_status = SMBus_PEC_Pass; // PEC 字节已验证 } 其他 {smbus_access_status = SMBus_PEC_FAIL; // PEC 测试失败 } } /* *函数名称:I2C/SMBus 中断矢量服务例程(USCI B1) * 说明:此 ISR 在 主从配置中将 MSP430 I2C USCI 模块配置为 RX 和 TX * SMBus 命令和数据。 *** / #pragma vector = USCI_B1_vector __interrupt void USCI_B1_ISR (void) { switch (_even_in_range (UCB1IV、12)) }{ 情况0: 中断; 案例2: // ALIFG 中断; 案例4: // NACKIFG UCB1CTLW1 |= UCTXSTP; //发送停止 UCB1IFG &=~UCNACKIFG; //清除 NACK 标志 _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0 RXFlag = FLAG_NACK; //数据操作失败 TXFlag = FLAG_NACK; //数据操作失败 中断; 案例6: // STTIFG TA1CTL = TASSEL_ACLK + TACLR + MC_UP; SMBus_Start_Flag = SMBus_start_FLAG_set; 中断; 案例8: // STPIFG _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0 RXFlag = FLAG_SUCCESS; //将接收到的数据 RX 标志设置为成功 中断; 案例10: // RXIFG IF (RWFlag = SMBus_MASTER_MODE_READ) { RXByteCounter--; //递减 RX 字节计数器 IF (RXByteCounter) { *pRXData+= UCB1RXBUF; //剩余要接收的多个字节 TA1CTL = tassel_ACLK + TACLR + MC_UP; } 其他 { *pRXData= UCB1RXBUF; //要接收的最后一个字节 _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0 RXFlag = FLAG_SUCCESS; //将接收到的数据 RX 标志设置为成功 } if (RXByteCounter = 1) //只剩下一个字节? UCB1CTLW1 |= UCTXSTP; //生成 I2C 停止条件 //如果只读取1个字节,则停止条件 //应该已经发送 } 否则、如果(RWFlag = SMBus_SLAVE_MODE_WRITE) { *pRXData++= UCB1RXBUF; //将每个接收到的字节填充到数组 中} 中断; 情况12: // TXIFG //当 UCB1TXBUF 为空时置1 IF (RWFlag = SMBus_MASTER_MODE_READ) { IF (TXByteCounter) //如果有要传输的内容 { UCB1TXBUF =*pTXData++; //加载 TX 缓冲区 TXByteCounter--; //测量 TX 字节计数器 RXFlag = FLAG_SUCCESS; } 其他 //无需再传输 { UCB1CTLW1 &=~UCTR; //接收器模式 UCB1IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志 UCB1CTLW1 |= UCTXSTT; // I2C 重新启动(SMBus 协议) if (RXByteCounter = 1){ //只接收一个字节? //请参阅 USCI - I2C 模式中的 I2C 主接收器模式部分 // 5xx 系列用户指南的一章(SLAU208G -第607页) while (UCB1CTLW1和 UCTXSTT); //已发送开始条件轮询 UCB1CTLW1 |= UCTXSTP; //生成 I2C 停止条件 } } 否则、如果(RWFlag = SMBus_MASTER_MODE_WRITE) { IF (TXByteCounter) //如果有要传输的内容 { UCB1TXBUF =*pTXData++; //加载 TX 缓冲区 TXByteCounter--; //测量 TX 字节计数器 TXFlag = FLAG_SUCCESS; } 其他 { UCB1CTLW1 |= UCTXSTP; // I2C 停止条件 UCB1IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志 _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0 TXFlag = FLAG_SUCCESS; } } TA1CTL = TASSEL_ACLK + TACLR + MC_UP; 中断; 默认值: 中断; }
谢谢、
您好、Mauro、
我看到两个可能的问题:
要检查它是否是上升沿问题、请降低波特率。 (您可以使用的最小值为10kHz)
如果是外设逻辑问题、我建议您查看 Resource Explorer 中的示例代码。
在 CCS 中、在"View"菜单下或在以下地址在线:
在 Resource Explorer 中、转到以下路径:
软件-> MSP430Ware XXXX ->开发工具-> MSP-EXP430FR5994 ->外设示例->寄存器级-> MSP430FR5994
在该文件夹下、查找以 msp430fr599x_euscib_i2c._xxx 开头的文件
此外、请在附近查看 MSP430FR599x 的用户指南以进行检查
此致、
米歇尔
代码如下:
#include
#include
#define BQ78350_ADDR (0x16>>>1)
#define MFR_BLK_ACCESS 0x44
#define MAX_queue 75
#define MAX_RX_LEN 50
#define MAX_TX_LEN 10
#define CRC8_Poly 0x07
#define CRC8_INIT_REM 0x00
int flag_50ms;
int flag_100ms;
int flag_500ms;
int flag_1000ms;
int flag_2000ms;
int time = 0;
int count_50ms;
int count_100ms;
int count_500ms;
int count_1000ms;
int count_2000ms;
unsigned char batt_data_buffer[2]={0x00、0x00};
unsigned char 电压;
typedef struct message_t{
无符号字符地址;
unsigned char mess_dir;
unsigned char is 块;
unsigned char TX_DATA[MAX_TX_LEN];
unsigned int tx_cnt;
unsigned char * rx_data;
unsigned int rx_cnt;
unsigned char nack;
void (* rx_done 回调)(unsigned char);
unsigned char id;
}message;
typedef struct message_queue_t{
消息 mess_q[MAX_QUE];
unsigned int mess_q_cnt;
unsigned int mess_q_in;
unsigned int Poly_q_out;
}message_queue;
静态 unsigned char crc8MakeBitwise (unsigned char CRC、unsigned char Poly、unsigned char * Pmsg、unsigned int Msg_size);
smbus_state cur_state = smbus_idle;
unsigned int error_flag;
unsigned int TX_don_flag;
unsigned int mess_delay
unsigned long nack_cntr;
volatile message * cur_mess;
message_queue smbus_queue;
volatile unsigned char * ptxData;
volatile unsigned char
TXByteCtr;
volatile unsigned char RXByteCtr;
unsigned char read_mess= 1;
unsigned char write_mess= 0;
unsigned int smbus_Is_running (void){void}
return (smbus_queue.mess_q_cnt > 0);
}
unsigned int smbus_get_error (void){
返回 ERROR_FLAG;
}
void smbus_read_nack (void){
__no_operation();
}
无符号字符 smbus_is_queue_full (void){
if (smbus_queue.mess_q_cnt = MAX_queue)
返回1;
返回0;
}
smbus_state smbus_get_state (void){
返回 cur_state;
}
void smbus_q_init (void){
SMBus_queue.mess_q_cnt = 0;
SMBus_queue.mess_q_in = 0;
SMBus_queue.mess_q_out = 0;
}
//此函数假设 SMBus 模块已正确配置。
void smbus_reset (void){
UCB2CTLW0 |= UCTXSTP;//立即强制停止
TA1CTL = MC__STOP; //停止超时计数器
UCB2CTLW0 |= UCSWRST; //重置 SMBus 模块
CUR_ST态= smbus_down;
}
void smbus_resume (void){
UCB2CTLW0 &=~UCSWRST;//启用 SMBus 模块
}
//返回1 (如果有正在处理的消息)。 否则、返回0。
unsigned char smbus_process (void){
//unsigned char stream[MAX_RX_LEN + MAX_TX_LEN];
如果(ERROR_FLAG = 1){
CUR_ST态= smbus_no_resp;
}
如果(ERROR_FLAG = 2){
CUR_ST态= smbus_failure;
}
CUR_mess=&smbus_queue.mess_q[smbus_queue.mess_q_out];
开关(cur_state){
案例 smbus_idle:
case smbus_wait:
if (smbus_queue.mess_q_cnt > 0){
IF (UCB2STAT 和 UCBBUSY){
CUR_ST态= smbus_wait;
}
否则{
ERROR_FLAG = 0;
mess_DONE_FLAG = 0;
TX_DONE_FLAG = 0;
Timer_delay_over = 1;
CUR_ST态= smbus_delay;
}
}
否则{
CUR_ST态= smbus_idle;
返回0;
}
中断;
case smbus_delay:
如果(timer_delay_over = 1){
PTxData =(unsigned char *)(&cur_mess->TX_DATA[0]);
PRxData =(unsigned char *)(&cur_mess->rx_data[0]);
TXByteCtr = cur_mess->TX_cnt;
RXByteCtr = cur_mess->rx_cnt;
IF (UCB2CTLW0和 UCTXSTP){ //是否发送停止条件?
中断;
}
CUR_ST态= smbus_tx; //更改发送状态
TA1CTL = tassel_SMCLK | TACLR | MC__Continuous | TAIE;//开始延迟
UCB2CTLW0 |= UCTR | UCTXSTT; // I2C TX,启动条件
}
中断;
案例 smbus_done:
/*
*目前已忽略 PEC
if (cur_mess->mess_dir = read_mess){
STREAM [0]=(UCB2I2CSA << 1)&~0x01;
stream[1]= cur_mess->address;
对于(i = 0;i < cur_mess->TX_cnt;i++){
stream[i + 1]= cur_mess->TX_DATA[i];
}
stream[cur_mess->tx_cnt]= cur_mess->address | 0x01;
对于(i = 0;i < cur_mess->rx_cnt;i++){
stream[i + cur_mess->TX_cnt + 1]= cur_mess->rx_data[i];
}
PEC = crc8MakeBitwise (CRC8_INIT_REM、CRC8_Poly、&(STREAM[0])、
cucr_mess->tx_cnt + cur_mess->rx_cnt + 2);
if (PEC =* PRxData){
//更新状态机的 BQ78350数据
//P1OUT ^= 0x01;
}
//否则{PEC}中的//错误
}
*
//else {我们有一条仅 TX 消息}
如果(smbus_queue.mess_q_cnt > 0){//删除最后一个消息队列
if (cur_mess->mess_dir = read_mess){
if (cur_mess->NACK)
Nack_cntr++;
//无错误地完成读取,跳转至回调(如果有)。
否则(cur_mess->rx_done 回调)
(CUR_mess->Rx_DONE_CALLBACE)(cur_mess->id);
}
否则(cur_mess->nack){
Nack_cntr++;
}
SMBus_queue.mess_q_out++;
if (smbus_queue.mess_q_out = MAX_queue) smbus_queue.mess_q_out = 0;
SMBus_queue.mess_q_cnt--;
}
CUR_ST态= smbus_wait;
中断;
案例 smbus_tx:
如果(TX_DONE_FLAG) cur_state = smbus_Rx;
//Drop Through
案例 smbus_Rx:
如果(mess_done 标志) cur_state = smbus_done;
中断;
案例 smbus_down:
案例 smbus_failure:
案例 smbus_no_resp:
//不执行任何操作
中断;
默认值:
CUR_ST态= smbus_wait;
中断;
}
返回1;
}
void battery_rx_done (unsigned char id){
switch (id){
case 0://voltage
电压= batt_data_buffer[0]|(batt_data_buffer[1]<< 8);
break;
默认值:break;
}
void smbus_requestWord (unsigned char addr、unsigned char id、unsigned char * return_data、void (* rx_do回 调)(unsigned char))){
消息*new_mess;
if (smbus_queue.mess_q_cnt < MAX_queue){
new_mess=&smbus_queue.mess_q[smbus_queue.mess_q_in];
//将数据添加到消息队列
new_mess->address = BQ78350_ADDR;
new_mess->mess_dir = read_mess;
new_mess->is 块= 0;
new_mess->TX_DATA[0]= addr;
new_mess->TX_cnt = 1;
new_mess->Rx_data = return_data;
new_mess->rx_cnt = 3;
new_mess->NACK = 0;
new_mess->Rx_done 回调= Rx_done 回调;
new_mess->id = id;
//更新队列指针
SMBus_queue.mess_q_in++;
如果(smbus_queue.mess_q_in = MAX_queue) smbus_queue.mess_q_in = 0;
SMBus_queue.mess_q_cnt++;
}
}
void smbus_init (void){
TA1CCTL0 = CCIE; //启用 TACCR0中断
TA1CCTL1 = CCIE; //启用 TACCR1中断
TA1CCTL2 = CCIE; //启用 TACCR2中断
TA1CCR0 = 5000;
TA1CCR1 = 1000;
TA1CCR2 = 12500;
TA1CTL = tassel_SMCLK | MC__Continuous; // SMCLK、连续模式
//为 I2C 配置 GPIO
P7SEL0 |= BIT0 | BIT1;
P7SEL1 &=~(BIT0 | BIT1);
//将 USCI_B2配置为 I2C 模式
UCB2CTLW0 = UCSWRST; //将 eUSCI_B 置于复位状态
UCB2CTLW0 |= UCMODE_3 | UCMST | UCSSEL_SMCLK;// I2C 主控模式、SMCLK
UCB2BRW = 0x64; //波特率= SMCLK /8
UCB2CTLW0 &=~UCSWRST; //清除复位寄存器
UCB2IE |= UCTXIE0 | UCNACKIE; //发送和 NACK 中断使能
UCB2I2CSA = BQ78350_ADDR; //配置从地址
CUR_ST态= smbus_idle;
ERROR_FLAG = 0;
Timer_delay_over = 0;
TX_DONE_FLAG = 0;
mess_DONE_FLAG = 0;
Nack_cntr = 0;
SMBus_q_init();
}
int main (void){
WDTCTL = WDTPW | WDTHOLD; //停止 WDT
//配置 GPIO
P1DIR |= BIT0; // LED 1.0
P1OUT |= BIT0;
P1DIR |= BIT1; // LED 1.2
P1OUT |= BIT1;
P1DIR |= BIT2; // GPIO 1.2
P1OUT |= BIT2;
PJSEL0 |= BIT4 | BIT5; // XT1
//禁用 GPIO 上电默认高阻抗模式以激活
//先前配置的端口设置
PM5CTL0 &=~LOCKLPM5;
//时钟
CSCTL0_H = CSKKEY_H; //解锁 CS 寄存器
CSCTL1 = DCOFSEL_0; //将 DCO 设置为1MHz
CSCTL2 = SELA_LFXTCLK | SELESS__DCOCLK | SELM_DCOCLK;//设置 ACLK = XT1;MCLK = DCO
CSCTL3 = DIVA__1 | DIVM_1 | DIVM__1;//将所有分频器设置为1
CSCTL4 &=~LFXTOFF;
操作
{
CSCTL5 &=~LFXTOFFG; //清除 XT1故障标志
SFRIFG1 &=~OFIFG;
} while (SFRIFG1和 OFIFG); //测试振荡器故障标志
CSCTL0_H = 0; //锁定 CS 寄存器
_enable_interrupt ();
SMBus_init();
SMBus_resume();
while (1){
SMBus_requestWord (0x09、0、batt_data_buffer、battery_rx_done);
SMBus_process();
}
}
#if defined (__TI_Compiler_version__)|| defined (__IAR_systems_ICC__)
#pragma vector = EUSCI_B2_vector
__interrupt void USCI_B2_ISR (void)
#Elif defined (__GNU__)
void __attribute__(interrupt (eUSCI_B2_vector))#USCI_B2_ISR (void Ub2_vector)
)(void UCI_B2_BUF Compiler_B2_b2_b2_b2)(void Ub2编译器#
#endif
{
开关(__evo_in_range (UCB2IV、USCI_I2C_UCBIT9IFG))
{
USCI_NONE 案例: 中断; //向量0:无中断
USCI_I2C_UCALIFG 案例:中断; //向量2:ALIFG
USCI_I2C_UCNACKIFG 案例: //向量4:NACKIFG
UCB2CTLW0 |= UCTXSTP; //发送停止
UCB2IFG &=~UCNACKIFG; //清除 NACK 标志
TA1CTL = MC__STOP; //关闭超时计时器
CUR_mess->NACK = 1; //事务失败。 ISR 处理后无需唤醒。
mess_DONE_FLAG = 1;
中断;
案例 USCI_I2C_UCSTTIFG:中断; //向量6:STTIFG
案例 USCI_I2C_UCSTPIFG:中断; //向量8:STPIFG
USCI_I2C_UCRXIFG3案例:中断; //向量10:RXIFG3
USCI_I2C_UCTXIFG3案例:中断; //向量12:TXIFG3
USCI_I2C_UCRXIFG2案例:中断; //向量14:RXIFG2
USCI_I2C_UCTXIFG2案例:中断; //向量16:TXIFG2
USCI_I2C_UCRXIFG1案例:中断; //向量18:RXIFG1
USCI_I2C_UCTXIFG1案例:中断; //向量20:TXIFG1
USCI_I2C_UCRXIFG0案例: //向量22:RXIFG0
TA1CTL = MC__STOP; //关闭超时计时器
RXByteCtr---; //递减 RX 字节计数器
if (RXByteCtr){
* PRxData = UCB2RXBUF; //剩余要接收的多个字节
PRxData++;
//if 块访问、第一个字节是块长度
RXByteCtr =(cur_mess->is 块)? (UCB2RXBUF +1):RXByteCtr;
//复位是块标志,因此长度只更新一次
CUR_mess->IS 块= 0;
TA1CTL = tassel_SMCLK | TACLR | MC__Continuous | TAIE;//开始延迟
}
否则{
* PRxData = UCB2RXBUF; //要接收的最后一个字节
mess_DONE_FLAG = 1; //显示读取完成的标志
__BIC_SR_REGISTER_ON_EXIT (LPM3_BITS);//退出 LPM3,因为在读取后有一些处理要执行
}
IF (RXByteCtr = 1) //只剩下一个字节?
UCB2CTLW0 |= UCTXSTP; //生成 I2C 停止条件
//如果只读取1个字节,则停止条件
//应该已经发送
中断;
USCI_I2C_UCTXIFG0案例: //向量24:TXIFG0
TA1CTL = MC__STOP; //关闭超时计时器
IF (TXByteCtr) //如果有要传输的内容
{
UCB2TXBUF =* PTxData++; //加载 TX 缓冲区
TXByteCtr --; //测量 TX 字节计数器
TA1CTL = tassel_SMCLK | TACLR | MC__Continuous | TAIE;//开始延迟
}
//无需再传输
否则、如果(cur_mess->mess_dir = read_mess){//更改为接收模式
UCB2CTLW0 &=~UCTR; //接收器模式
UCB2IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志
UCB2CTLW0 |= UCTXSTT; // I2C 重新启动(SMBus 协议)
TX_DONE_FLAG = 1;
TA1CTL = tassel_SMCLK | TACLR | MC__Continuous | TAIE;//开始延迟
}
否则{ //仅发送,停止传输
UCB2CTLW0 &=~UCTR;
UCB2IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志
UCB2CTLW0 |= UCTXSTP; //生成 I2C 停止条件
CUR_ST态= smbus_done; //显示读取完成的标志
mess_Done 标志= 1;
}
中断;
案例 USCI_I2C_UCBCNTIFG:break; //向量26:BCNTIFG
USCI_I2C_UCCLTOIFG 案例:中断; //向量28:时钟低电平超时
USCI_I2C_UCBIT9IFG 案例:中断; //向量30:第9位
默认值:break;
}
}
#pragma vector = Timer1_A0_vector
__interrupt void Timer1_A0_ISR (void)
{
count_50ms++;
count_100ms++;
count_500ms++;
count_1000ms++;
count_2000ms++;
如果(count_50ms>=5){count_50ms = 0;flag_50ms = 1;}
如果(count_100ms>=10){count_100ms = 0;flag_100ms = 1;}
如果(count_500ms>=50){count_500ms = 0;flag_500ms = 1;}
如果(count_1000ms>=100){count_1000ms = 0;flag_1000ms = 1;}
如果(count_2000ms>=200){count_2000ms = 0;flag_2000ms = 1;}
TA1CCR0 += 5000;
}
#pragma vector = Timer1_A1_vector //针对 CCR1、CCR2
__interrupt void Timer1_A1_ISR (void)
{
switch (TA1IV){
情况0x02: // CCR1
TA1CTL = MC__STOP; //关闭超时计时器
TA1CCTL1 = 0; //禁用此比较点
Timer_delay_over = 1; //将标志设置为结束延迟
TA1CCR1 += 1000;
中断;
情况0x04: // CCR2
TA1CTL = MC__STOP; //关闭超时计时器
UCB2CTLW0 |= UCTXSTP; //在 SDA 线上发送 STOP
UCB2CTLW0 |= UCSWRST; //启用 SW 复位
UCB2CTLW0 &=~UCSWRST;
UCB2IE |= UCTXIE + UCRXIE + UCNACKIE;//启用 TX、RX、NACK 中断
ERROR_FLAG = 2; //超时标志
TA1CCR2 += 12500;
中断;
}
}
您好、Mauro、
参考手册中给出的 BQ78350地址已移位。 即:当您从器件读取时、微控制器应发送0x16作为其第一个字节、并在您写入时发送0x17。 MSP430F5338微控制器需要用户设置从器件地址、以在主模式下设置 I2C。 在有效载荷中、包含地址的第一个字节必须移回才能正确发送。 请确保阅读 UC 用户指南以正确配置 I2C 外设。
SDA 和 SCL 线路在发送或接收后都应变为高电平、如果情况并非如此、那么您的微控制器会出于某种原因挂起线路。 我假设您在线路上有上拉电阻器。
根据您提供的信息、可能是 I2C 外设未配置或逻辑不正确。
遗憾的是、我没有时间检查代码和进行调试、但下面是建议的调试步骤:
打开 Software -> MSP430Ware xxx -> Libraries -> SMBusLib
下载内容:
此致、
米歇尔
您好、Michel。
每次发送 smbus_requestWord ()/smbus_requestMfrAccessReg ()时,我都必须调用 smbus_process()函数,还是有其他方法可以执行这些任务?
我问这个、因为我看到有队列逻辑、但我不理解。
int main (void){ WDTCTL = WDTPW | WDTHOLD; //停止 WDT init_gpio(); init_clock(); init_timer0(); _enable_interrupt (); SMBus_init(); SMBus_resume(); while (1){ SMBus_requestWord (0x0E、0、batt_data_buffer、battery_rx_done); SMBus_process(); SMBus_requestWord (0x09、1、batt_data_buffer、battery_rx_done); SMBus_process(); } }
谢谢、
您好、Mauro、
该过程是一个状态机、用于监控发送/接收的消息。 所有的消息处理都是通过中断(在后台)完成的、并且过程会检查中断的哪个步骤。 因此、每次运行该函数时、它只能"前进"一步。
简单地说、器件进入该过程、检查状态是否已更改、在必要时执行任何操作并退出。 这使得 SMBus 的工作方式与非阻塞功能相似。 这使您可以在发送 SMBus 消息时执行其他操作。 例如、您可以同时处理 UART 端口上的数据。
当您有操作系统时、所有这些操作都将在后台处理、而无需注意任何事项。 如果没有操作系统、则需要显式执行此操作。
话虽如此、您必须尽可能频繁地进入 smbus_process。 如果您有任何类似 SMBus 的其他进程、请确保它们也不会阻止、因为它会阻止 SMBus 执行并导致错误。 这也意味着您不能在代码中使用任何睡眠函数。
那么、这里有一些应该有所帮助的伪代码
while (1){ //更新状态机 smbus_process (); //出于 此伪代码的目的,我们假设您有一个运行 //的计时器,并且您正在检查该时间段是否已过去。 if (一些电池超时){ //这将排队两条消息。 它们将一个接一个地被处理。 //您可以将许多消息排队。 您可以检查数据是否已保存 //通过 SMBus 回调设置一些变量来接收。 //只需确保队列中的消息数不会超过 smbus 可以处理的消息数。 //(即确保超时时间足够长,以便在排队新消息之前发送所有消息) SMBus_requestWord (0x09、1、batt_data_buffer、battery_rx_done); SMBus_requestWord (0x0E、0、batt_data_buffer、battery_Rx_done); }
我希望这能为您清除问题。
此致、
米歇尔
您好、Michel。
很抱歉打扰了您、但您的帮助对我的项目非常重要。
我正在执行一些测试、现在我尝试从 bq76940EVM 读取一些变量并发送一些命令。 例如、我每500ms 读取一次电池的电压、并每2000ms 发送一条命令来打开/关闭 FET。 但是、在我获得读数后、当 FET 环路被执行时、我的 uC 会进入 ISR_TRAP 状态。 命令已发送、但代码在发送后停止。
;------------------------------------------------------------------ ;--如果用户不提供,则缺省 ISR 处理程序 ;--只需将设备放入 lpm0 中;--------------------------- .sect".text:_ISR:_TI_ISR_TRAP" .align2 .global__TI_ISR_TRAP __TI_ISR_TRAP: BIS.W #(0x0010)、SR JMP _TI_ISR_TRAP NOP
我的代码结构如下:
while (1){ SMBus_process(); if (timer&(1<<2)){//此循环每500ms 执行一次 SMBus_requestWord (CellVoltage15、_CellVoltage15、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage14、_CellVoltage14、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage13、_CellVoltage13、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage12、_CellVoltage12、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage11、_CellVoltage11、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage10、_CellVoltage10、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage9、_CellVoltage9、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage8、_CellVoltage8、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage7、_CellVoltage7、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage6、_CellVoltage6、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage5、_CellVoltage5、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage4、_CellVoltage4、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage3、_CellVoltage3、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage2、_CellVoltage2、batt_data_buffer、battery_rx_done); SMBus_requestWord (CellVoltage1、_CellVoltage1、batt_data_buffer、battery_rx_done); 定时器&=~BIT2;//flag = 0; P1OUT ^= BIT1;//呈绿色闪烁 LED; } if (timer&(1<<4)){//此循环每2000ms 执行一次 SMBus_requestMfrAccessReg (0x22、100、batt_data_buffer、battery_Rx_DONE);//FET 控制 定时器&=~BIT4;//flag = 0; P1OUT ^= BIT1;//闪烁红色 LED; }
我出了什么问题?
谢谢、
您好、Mauro、
我不会有太大帮助、因为这是一个微控制器问题、您必须自行对其进行调试。
但是、您可以查看以下一些内容:
很抱歉、我无法提供更多帮助。
此致、
米歇尔
您好、Mauro、
遗憾的是、我没有时间查看您提供的流程图。 我认为状态图更适合表示 SMBus 状态机的逻辑。 这将更易于理解。
[引用 user="Mauro Basquera"-我应该如何处理 smbus_failure? 为此,我将使用 smbus_init()和 smbus_resume()。 是否有更好的方法来重新初始化通信?
我复位我的 SMBus。 因此,SMBUS_init()后跟 SMBUS_RESUME 是最好的方法。 我们遇到了一个问题、即25ms 超时并不总是由 BQ78350重新指定、因此我们会经常进入这个条件。 我们通过将延迟增加到26ms 来解决了该问题。
[引用 user="Mauro Basquera"]-首次运行后 timer_delay_over 标志永远不会变为零。 为什么? 此代码标志的功能是什么?
我不是最后一个处理代码的人、但你认为它似乎没有被使用是对的。 BQ78350规定了 SMBus 通信之间的最小延迟为2ms。 该标志用于插入该延迟。 我不确定最后一位用于实施延迟的人员是什么。
此致、
米歇尔
您好、Michel。
我正在尝试使用 smbus_writeWord 函数更新 RemainingCapacity、但该命令不起作用。
我必须在命令之前或之后发送命令吗? 我已经选中、器件为"完全访问模式"。
unsigned char * dado; unsigned char x1; x1 = 0; dado =&x1; smbus_writeWord (0x0F、dado);
我有点困惑、因为我能够通过 bqStudio 更新 RemainingCapacity、但在 d/s 中、此命令仅显示为一个读取字。
同时作为 R/W 字:
谢谢、
您好、Mauro、
有几件事情看起来是错误的:
首先、17.17说明说它是一个读取字函数(而不是读取-写入)。 但是、您似乎可以通过 BQ Studio 对其进行配置。 这可能需要 TI 员工澄清。
是否确定未配置剩余电量警报?
我会将您转至论坛:看看是否有其他人已经问过这个问题、如果没有、则发布一个新问题。 通过提出新问题、其他论坛用户将查看并可能回答您的问题(IMO、此主题太长、包含的问题和答案太多。 我喜欢有一个主题、一个问题、一个答案)。
其次、您尝试发送一个字(2个字节)、但将一个无符号字符(1个字节)传递给函数。 我不确定该函数的行为是什么、但很可能是在 SMBus 线路上发送1个额外的字节的垃圾。
为了使您的代码更紧凑、我建议使用如下所示的代码:
//根据您的微控制器、这可能是 unsigned int 或 unsigned short。 //使用 uint16_t (有时是 uint16)更安全、uint16_t x1 = 0; smbus_writeWord (0x0F、&x1);
此致、
米歇尔
您好、Michel。
好的、我将尝试与 TI 员工进行澄清。
很抱歉这个长线程、但我在这里问它、因为它与您善意提供的代码相关。 你无法想象它对我有多大帮助。 我对嵌入式编程非常陌生、您可能已经注意到了这一点。
关于您建议的解决方案、它不起作用。 我将其作为 char 放置、因为该函数的输入被声明为 char。 当我放置 uint16_t 时、我收到警告:"#169-D 参数"类型为 unsigned short *"与"unsigned char *"类型的参数不兼容
void smbus_writeWord (unsigned char addr、unsigned char *数据){ 消息*new_mess; if (smbus_queue.mess_q_cnt < MAX_queue){ new_mess=&smbus_queue.mess_q[smbus_queue.mess_q_in]; new_mess->address = BQ78350_ADDR; new_mess->mess_dir = write_mess; new_mess->is 块= 0; new_mess->TX_DATA[0]= addr; new_mess->TX_DATA[1]=*数据; new_mess->TX_DATA[2]=*(data + 1); //更新队列指针 SMBus_queue.mess_q_in++; 如果(smbus_queue.mess_q_in = MAX_queue) smbus_queue.mess_q_in = 0; SMBus_queue.mess_q_cnt++; } }
我还尝试了其他变体、将数据直接放在 TX_DATA[1]和[2]上、但它不起作用。
我很确定用于更新 RemainingCapacity 的命令是0x0F、因为我在 bqStudio 中使用它。
非常感谢你的帮助。 我非常感谢。
您好、Mauro、
对于剩余的容量问题、请尝试写入另一个寄存器以确保写入字函数正常工作。
我使用 unsigned char *使函数成为通用函数。
然后、用户可以将其与 uint16_t (带有 cast)或 uint8_t 的数组一起使用 请参阅以下示例:
// uint16_t uint16_t x = 0x1234; smbus_writeWord (0x0F、(unsigned char *)&x); //使用数组 uint8_t y[2]; y[0]= 0x34; y[1]= 0x12; smbus_writeWord (0x0F、y);
最好使用第二种方法、因为您可以控制端字节序(使代码可移植、避免在您更改为其他微控制器时出现意外)。
此致、
米歇尔
编辑:此外、为了确保 BQ Studio 发送的内容、请使用逻辑分析仪。 您将能够准确地查看发送的命令。
您好、Michel。
非常感谢您的帮助。
它恰好是 smbus_writeWord 函数中缺少的一行。
new_mess->address = BQ78350_ADDR; new_mess->mess_dir = write_mess; new_mess->is 块= 0; new_mess->TX_cnt = 3;//我添加了此行 new_mess->TX_DATA[0]= addr; new_mess->TX_DATA[1]=*数据; new_mess->TX_DATA[2]=*(data+1);
我之所以解决这个问题、是因为我使用了示波器、uC 只是发送 bq78350地址、然后将线路拉高以获取任何地址和数据。
我不知道它是如何处理您的产品的、但我添加了它、它运行得很好。
感谢您的提示!
此致、
我对 SMB (或 I2C)没有太多经验、但可能有一些指导。 首先、在 I2C 基础上增加了一些 SMB 限制、因此熟悉 I2C 是一个很好的起点。 如果不仔细检查、我就看不到 I2C 所需的 Start、Ack、Nak 或 Stop 位。 我建议在 TI 网站上查看 slua475.pdf、作为一个良好的起点。
此外、我不确定有多少读者会浏览您发布的代码量。 或者更详细地说、我个人不会编写这么多的代码、直到我进行通信。 如果不深入研究、我不知道您是在 SW 中生成每个位、还是使用和 I2C 控制器、但无论采用哪种方法、可能有20行代码允许您生成读取请求并获得应答。 在这种情况下工作之前、其余部分会分散注意力。 更好的方法是执行写请求、因为它更简单、但它必须是导致可观察行为的东西、以便您可以判断它何时起作用。 最简单的写入请求只有四个字节长。