BMS STM32 V4.0.0.0
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file spi.c
|
||||
* @author
|
||||
* @version
|
||||
* @date
|
||||
* @brief SPI通信程序,用于与AFE芯片(SH3673520)通信
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f10x.h"
|
||||
#include "global.h"
|
||||
|
||||
//SH3673517 SPI通信
|
||||
//PB12 = SPI1_CS (GPIO推挽输出,软件控制片选)
|
||||
//PB13 = SPI1_SCK (AF1) - 时钟
|
||||
//PB14 = SPI1_MISO(AF1) - 主机输入从机输出
|
||||
//PB15 = SPI1_MOSI(AF0) - 主机输出从机输入
|
||||
#define PIN_SPI_NSS GPIO_Pin_12
|
||||
#define PIN_SPI_SCK GPIO_Pin_13
|
||||
#define PIN_SPI_MISO GPIO_Pin_14
|
||||
#define PIN_SPI_MOSI GPIO_Pin_15
|
||||
|
||||
#define SPI_Enable() GPIO_ResetBits(GPIOB, PIN_SPI_NSS) //使能通信
|
||||
#define SPI_Disable() GPIO_SetBits(GPIOB, PIN_SPI_NSS) //关闭通信
|
||||
|
||||
|
||||
/*
|
||||
SPI_MOSI PB15 主设备输出,从设备输入
|
||||
SPI_MISO PB14 主设备输入,从设备输出
|
||||
SPI_SCK PB13 时钟
|
||||
SPI_CS PB12 片选信号
|
||||
*/
|
||||
void uf_SPI2_Init(void)
|
||||
{
|
||||
/*定义SPI参数*/
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
SPI_InitTypeDef SPI_InitStructure;
|
||||
|
||||
// 使能SPI2和GPIOB时钟
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
|
||||
|
||||
// PB13 (SCK), PB15 (MOSI)
|
||||
GPIO_InitStructure.GPIO_Pin = PIN_SPI_SCK | PIN_SPI_MOSI;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
// PB14 (MISO)
|
||||
GPIO_InitStructure.GPIO_Pin = PIN_SPI_MISO;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
// PB12 (CS)
|
||||
GPIO_InitStructure.GPIO_Pin = PIN_SPI_NSS;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
GPIO_SetBits(GPIOB, PIN_SPI_NSS); //初始化拉高CS,关闭SPI通信
|
||||
|
||||
|
||||
/*配置SPI模式*/
|
||||
SPI_I2S_DeInit(SPI2);
|
||||
|
||||
// 配置SPI2与AFE芯片的SPI3通信方式:4线通信,全双工,主模式,数据同边传输,MSB在前
|
||||
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全双工模式
|
||||
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主模式
|
||||
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //数据帧大小为 8 位
|
||||
// 配置SPI3极性参数CPOL和CPHA
|
||||
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //时钟极性为1,空闲时SCK电平状态为高电平
|
||||
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //时钟相位为1,在第二个跳变沿开始采样数据(第一个跳变沿,失效)
|
||||
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //软件控制 NSS 信号(PB12)
|
||||
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;//波特率预分频系数为 64 //36MHz/64 = 0.5625MHz < 1MHz
|
||||
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //高位在前
|
||||
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值的生成多项式=x^8+x^2+x+1,省略高位,可为任意值1,只用到低8位,生成二进制编码为0000111=7
|
||||
SPI_Init(SPI2, &SPI_InitStructure);
|
||||
|
||||
// 使能SPI2
|
||||
SPI_Cmd(SPI2, ENABLE);
|
||||
}
|
||||
|
||||
//通信失败时,复位SPI
|
||||
void SPI2_Error(void)
|
||||
{
|
||||
//写也无法确有效,因为需要时序
|
||||
//这里重新初始化SPI
|
||||
uf_SPI2_Init();
|
||||
}
|
||||
|
||||
//AFE只支持单字节写操作
|
||||
//可写地址 40H~59H
|
||||
//rtnval 0-true; other-false
|
||||
uint8_t AFE_WriteOneByte(uint8_t addr, uint8_t *data)
|
||||
{
|
||||
uint8_t tx_buffer[5], rx_buffer[5];
|
||||
uint8_t i;
|
||||
uint8_t response;
|
||||
|
||||
// 构造发送数据帧: [0x01][reg_addr][write_data][CRC][0x00]
|
||||
tx_buffer[0] = 0x01; // 写命令
|
||||
tx_buffer[1] = addr; // 寄存器地址
|
||||
tx_buffer[2] = *data; // 写入数据
|
||||
tx_buffer[3] = CRC8_Cal(tx_buffer, 3); // CRC8
|
||||
tx_buffer[4] = 0x00; // 无效数据接收
|
||||
|
||||
// 拉低CS片选
|
||||
SPI_Enable();
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
|
||||
SPI_I2S_SendData(SPI2, tx_buffer[i]);
|
||||
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
rx_buffer[i] = SPI_I2S_ReceiveData(SPI2);
|
||||
}
|
||||
|
||||
// 获取返回值
|
||||
response = rx_buffer[4];
|
||||
|
||||
SPI_Disable();
|
||||
delay_us(5);
|
||||
|
||||
return (response == 0xA5) ? 0 : 1;
|
||||
}
|
||||
|
||||
//AFE可1次读取多个字节操作
|
||||
//可读取地址 40H~99H
|
||||
//rtnval 0-success, other-fail
|
||||
uint8_t AFE_ReadMulByte(uint8_t addr, uint8_t lenth, uint8_t *data)
|
||||
{
|
||||
uint8_t tx_buffer[4]; // 发送缓冲区
|
||||
uint8_t rx_buffer[40]; // 接收缓冲区,最大可读取24字节,留有余量
|
||||
uint8_t crc_calculated, crc_received;
|
||||
uint8_t i;
|
||||
|
||||
// 构造发送数据帧: [0x02][reg_addr][data_length][0x00]
|
||||
tx_buffer[0] = 0x02; // 读命令
|
||||
tx_buffer[1] = addr; // 寄存器地址
|
||||
tx_buffer[2] = lenth; // 数据长度
|
||||
tx_buffer[3] = 0x00;
|
||||
|
||||
// 拉低CS片选
|
||||
SPI_Enable();
|
||||
|
||||
// 第一阶段:发送时钟和命令,发送(命令/地址/长度/0x00) 接收(0xFF/命令/地址/长度)
|
||||
for( i=0; i<4; i++)
|
||||
{
|
||||
while(!SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)); // 等待发送缓冲区空
|
||||
SPI_I2S_SendData(SPI2, tx_buffer[i]);
|
||||
while(!SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)); // 等待接收完成
|
||||
rx_buffer[i] = SPI_I2S_ReceiveData(SPI2);
|
||||
}
|
||||
|
||||
// 第二阶段:接收有效数据(0x00)发送接收数据(需要提供接收时钟)
|
||||
for( i=0; i<lenth; i++)
|
||||
{
|
||||
while(!SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE));
|
||||
SPI_I2S_SendData(SPI2, 0x00); // 发送无效数据维持时钟
|
||||
while(!SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE));
|
||||
rx_buffer[4+i] = SPI_I2S_ReceiveData(SPI2);
|
||||
}
|
||||
|
||||
// 第三阶段:接收CRC
|
||||
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
|
||||
SPI_I2S_SendData(SPI2, 0x00);
|
||||
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
rx_buffer[4 + lenth] = SPI_I2S_ReceiveData(SPI2);
|
||||
|
||||
// 拉高CS片选
|
||||
SPI_Disable();
|
||||
delay_us(5);
|
||||
|
||||
// 校验应头(发送时同时接收)
|
||||
if(rx_buffer[0] != 0xFF || // 第一个字节应为0xFF
|
||||
rx_buffer[1] != 0x02 || // 回显读命令
|
||||
rx_buffer[2] != addr || // 回显寄存器地址
|
||||
rx_buffer[3] != lenth) // 回显数据长度
|
||||
{
|
||||
return 0; // 头部校验失败
|
||||
}
|
||||
|
||||
// 提取有效数据(跳过前4个应答字节)
|
||||
for (i = 0; i < lenth; i++)
|
||||
{
|
||||
data[i] = rx_buffer[4 + i]; // 跳过0xFF、命令、地址、长度
|
||||
}
|
||||
crc_received = rx_buffer[4 + lenth]; // 最后1字节为CRC
|
||||
|
||||
// CRC计算范围:0xFF + 命令 + 地址 + 长度 + 数据,直到CRC前
|
||||
crc_calculated = CRC8_Cal(&rx_buffer[0], 4 + lenth);
|
||||
|
||||
return (crc_received == crc_calculated) ? 0 : 1;
|
||||
}
|
||||
|
||||
//软件复位
|
||||
//rtnval 0-success, other-fail
|
||||
uint8_t AFE_Reset(void)
|
||||
{
|
||||
uint8_t tx_buffer[5], rx_buffer[5];
|
||||
uint8_t response;
|
||||
uint8_t i = 0;
|
||||
|
||||
// 构造发送数据帧: [0x0B][0xBB][0xCC][CRC][0x00]
|
||||
tx_buffer[0] = 0x0B; // 复位命令
|
||||
tx_buffer[1] = 0xBB; // 固定参数1
|
||||
tx_buffer[2] = 0xCC; // 固定参数2
|
||||
tx_buffer[3] = CRC8_Cal(tx_buffer, 3); // CRC8
|
||||
tx_buffer[4] = 0x00; // 无效数据接收
|
||||
|
||||
// 拉低CS片选
|
||||
SPI_Enable();
|
||||
|
||||
for ( i = 0; i < 5; i++)
|
||||
{
|
||||
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
|
||||
SPI_I2S_SendData(SPI2, tx_buffer[i]);
|
||||
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
|
||||
rx_buffer[i] = SPI_I2S_ReceiveData(SPI2);
|
||||
}
|
||||
|
||||
// 获取返回值
|
||||
response = rx_buffer[4];
|
||||
|
||||
// 拉高CS片选
|
||||
SPI_Disable();
|
||||
|
||||
return (response == 0xA5) ? 0 : 1;
|
||||
}
|
||||
Reference in New Issue
Block a user