GD32F303RCT6与RN8302B使用模拟SPI通讯

以下是基于 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;



}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诺水城子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值