以下是基于 GD32F303RCT6 微控制器与 RN8302B 电能计量芯片结合的软件实例开发指南。RN8302B 是一款高精度三相电能计量芯片,支持电压、电流、功率、电能等参数的测量,广泛应用于智能电表和工业电力监控系统。以下内容结合 GD32F303RCT6 的硬件特性及常见开发模式,提供关键实现步骤和代码示例。
硬件连接端口:

/********模拟SPI**********/
// 定义 SIP 引脚
#define SIP_SCK_PORT GPIOA
#define SIP_SCK_PIN GPIO_PIN_5
#define SIP_MOSI_PORT GPIOA
#define SIP_MOSI_PIN GPIO_PIN_7
#define SIP_MISO_PORT GPIOA
#define SIP_MISO_PIN GPIO_PIN_6
#define SIP_CS_PORT GPIOA
#define SIP_CS_PIN GPIO_PIN_4
void SIP_GPIO_Init(void) {
// 使能 GPIOA 时钟
rcu_periph_clock_enable(RCU_GPIOA);
// 配置 SCK 和 MOSI 为推挽输出
gpio_init(SIP_SCK_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SIP_SCK_PIN);
gpio_init(SIP_MOSI_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SIP_MOSI_PIN);
// 配置 MISO 为浮空输入
gpio_init(SIP_MISO_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, SIP_MISO_PIN);
// 配置 CS 为推挽输出,初始高电平
gpio_init(SIP_CS_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, SIP_CS_PIN);
gpio_bit_set(SIP_CS_PORT, SIP_CS_PIN);
}
// 发送一个字节
void SIP_SendByte(uint8_t data)
{
for (uint8_t i = 0; i < 8; i++) {
// 在 SCK 上升沿输出数据(模式0:CPOL=0, CPHA=0)
gpio_bit_write(SIP_MOSI_PORT, SIP_MOSI_PIN, (data & 0x80) ? SET : RESET);
data <<= 1;
DelayUs(1); // 保持数据稳定
gpio_bit_set(SIP_SCK_PORT, SIP_SCK_PIN); // SCK 拉高
DelayUs(1);
gpio_bit_reset(SIP_SCK_PORT, SIP_SCK_PIN); // SCK 拉低
DelayUs(1);
}
}
// 接收一个字节
uint8_t SIP_ReceiveByte(void)
{
uint8_t data = 0;
for (uint8_t i = 0; i < 8; i++) {
gpio_bit_set(SIP_SCK_PORT, SIP_SCK_PIN); // SCK 拉高
DelayUs(1);
data <<= 1;
if (gpio_input_bit_get(SIP_MISO_PORT, SIP_MISO_PIN)) {
data |= 0x01; // 读取数据位
}
gpio_bit_reset(SIP_SCK_PORT, SIP_SCK_PIN); // SCK 拉低
DelayUs(1);
}
return data;
}
// 发送并接收一个字节(全双工)
uint8_t SIP_TransferByte(uint8_t tx_data)
{
uint8_t rx_data = 0;
for (uint8_t i = 0; i < 8; i++)
{
// 发送数据
gpio_bit_write(SIP_MOSI_PORT, SIP_MOSI_PIN, (tx_data & 0x80) ? SET : RESET);
tx_data <<= 1;
// 时钟上升沿
gpio_bit_set(SIP_SCK_PORT, SIP_SCK_PIN);
DelayUs(1);
// 接收数据
rx_data <<= 1;
if (gpio_input_bit_get(SIP_MISO_PORT, SIP_MISO_PIN)) {
rx_data |= 0x01;
}
// 时钟下降沿
gpio_bit_reset(SIP_SCK_PORT, SIP_SCK_PIN);
DelayUs(1);
}
return rx_data;
}
void SIP_CS_Enable(void) {
gpio_bit_reset(SIP_CS_PORT, SIP_CS_PIN); // 拉低片选
DelayUs(10); // 确保从设备准备好
}
void SIP_CS_Disable(void) {
gpio_bit_set(SIP_CS_PORT, SIP_CS_PIN); // 拉高片选
DelayUs(10);
}
// 模拟读取从设备寄存器
uint8_t SIP_ReadRegister(uint8_t reg_addr)
{
SIP_CS_Enable();
SIP_SendByte(reg_addr | 0x80); // 发送读命令(假设最高位为读标志)
uint8_t data = SIP_ReceiveByte();
SIP_CS_Disable();
return data;
}
// 模拟写入从设备寄存器
void SIP_WriteRegister(uint8_t reg_addr, uint8_t data) {
SIP_CS_Enable();
SIP_SendByte(reg_addr & 0x7F); // 发送写命令(最高位为0)
SIP_SendByte(data);
SIP_CS_Disable();
}
RN8302B 初始化
void rn8302b_init(void)
{
SIP_GPIO_Init();
#if 1
uint32_t ver_tmp;
// 写使能位
RN8302b_Write_Register(0x0180,0xe5,1);
// 软件复位
RN8302b_Write_Register(0x182,0xfa,1);
DelayMs(30);
// 写使能位
RN8302b_Write_Register(0x180,0xe5,1);
ver_tmp = RN8302b_Read_Register(0x180,1);//读取电压有效值
printf(" 0x0180=%x\r\n",ver_tmp);
// 切换到EMM模式
RN8302b_Write_Register(0x181,0xA2,1);
ver_tmp = RN8302b_Read_Register(0x18A,2);//读取状态寄存器
printf(" Status 8A=%x\r\n",ver_tmp);
switch(ver_tmp>>14 &0x03)
{
case 0:
printf(" work Mode:NVM1\n");
break;
case 1:
printf(" work Mode:EMM\n");
break;
case 2:
printf(" work Mode:NVM2\n");
break;
case 3:
printf(" work Mode:SLM\n");
break;
}
#endif
printf("rn8302b_init over\n");
}
读电流电压
void RN8302b_Read_DataE(void)
{
int i;
uint32_t reg_value;
//读电压电流
for(i=0;i<4;i++)
{
reg_value = RN8302b_Read_Register(UA_CMD+i , 4 ) ; //读电压
reg_value &= 0x0FFFFFFF;
if (reg_value & 0x08000000) // 0x08000000 = 0b00001000_00000000_00000000_00000000
{
gFrontTmp.U[i]=(reg_value | 0xF0000000); // 3. 符号扩展:高4位填充1
}
else
{
gFrontTmp.U[i] = reg_value; // 符号位为0,直接返回
}
reg_value = RN8302b_Read_Register(IA_CMD+i , 4 ) ; //读电流
reg_value &= 0x0FFFFFFF;
if (reg_value & 0x08000000) // 0x08000000 = 0b00001000_00000000_00000000_00000000
{
gFrontTmp.I[i]= (reg_value | 0xF0000000); // 3. 符号扩展:高4位填充1
}
else
{
gFrontTmp.I[i] = reg_value; // 符号位为0,直接返回
}
}
//电压电流计算
g_PowerValue.A.U = (float)gFrontTmp.U[0]*g_Krmsx.Ua_krmsx/1000;
g_PowerValue.B.U = (float)gFrontTmp.U[1]*g_Krmsx.Ub_krmsx/1000;
g_PowerValue.C.U = (float)gFrontTmp.U[2]*g_Krmsx.Uc_krmsx/1000;
g_PowerValue.A.I = (float)gFrontTmp.I[0]*g_Krmsx.Ia_krmsx/1000;
g_PowerValue.B.I = (float)gFrontTmp.I[1]*g_Krmsx.Ib_krmsx/1000;
g_PowerValue.C.I = (float)gFrontTmp.I[2]*g_Krmsx.Ic_krmsx/1000;
g_PowerValue.Uab = g_Power_Value.A.U*1.732;
g_PowerValue.Ubc = g_Power_Value.B.U*1.732;
g_PowerValue.Uca = g_Power_Value.B.U*1.732;
}
422

被折叠的 条评论
为什么被折叠?



