这里以C相电压采集为例,来快速了解RN8302B的使用
①SPI引脚
具体原因参考《RN8302B 用户手册》:
1)1.1 芯片特性
2) 5.4 SPI 写时序
CPOL表示SCK空闲时间的状态,从时序图里可以看出CPOL=LOW
CPHA表示在第一边沿还是第二边沿进行数据交换,从时序图里可以看出CPOL=2 Edge
②控制引脚
将PB12配置为GPIO_Output模式,PC6配置为GPIO_Input模式
③呼吸灯
这里我是用的是PC1作为呼吸灯,其实不论使用哪个引脚控制的呼吸灯,只需将其重命名为LED1即可
然后右击引脚分别重命名(注意顺序:先左击配置模式,再右击重命名)
最终结果
生成代码
- #ifndef _SPI_H_
- #define _SPI_H_
-
- #include "main.h"
- #include "stdio.h"
-
- //---------------------- RN8302计量寄存器地址定义---------------------------------------------------//
- #define UC_CMD 0x0009//4//C相电压有效值
- #define UC_BYTE 4
-
- #define SYSSR_CMD 0x018A//系统状态寄存器
- #define SYSSR_BYTE 2
-
- #define DeviceID_CMD 0x018f//RN8302B Device ID
- #define DeviceID_BYTE 3
-
- #define SPI_CS_HIGH() HAL_GPIO_WritePin( RN_NSS_GPIO_Port , RN_NSS_Pin, GPIO_PIN_SET )
- #define SPI_CS_LOW() HAL_GPIO_WritePin( RN_NSS_GPIO_Port , RN_NSS_Pin, GPIO_PIN_RESET )
-
-
- void ReadAmmeterData(void);
-
- #endif
- /****************SPI 采用端口模拟**********************************/
- #include "rn8302b.h"
- #include "spi.h"
-
-
- /*****************SPI 写单字节**************************/
- void Write_SPI_OneByte(uint8_t TxData)
- {
- uint8_t Rxdata;
- HAL_SPI_TransmitReceive(&hspi2,&TxData,&Rxdata,1, 1000);
- return ;
- }
- /*****************SPI 读单字节**************************/
- uint8_t Read_SPI_OneByte(void)
- {
- uint8_t Rxdata;
- uint8_t TxData=0;
- HAL_SPI_TransmitReceive(&hspi2,&TxData,&Rxdata,1, 1000);
- return Rxdata;
- }
- /************************* READ_RN8302*************************************************/
- uint32_t READ_SPI(uint16_t Address,uint8_t Data_len)
- {
- uint8_t i, DTemp,CheckSumR;
- uint32_t drData;
-
- SPI_CS_LOW(); // 开启SPI传输
-
- DTemp = (uint8_t)(Address&0x00FF);//ADDR[7:0]
- CheckSumR = DTemp;
- Write_SPI_OneByte(DTemp);
- DTemp = (((uint8_t)(Address >> 4)) & 0xf0) ;//CMD=R/W+AD[10:8]+BL[1:0]+2’h0(MSB+LSB)
- CheckSumR += DTemp;
- Write_SPI_OneByte(DTemp);
-
- HAL_Delay(5);
- drData = 0x00000000;//Read 24bit
-
- for(i=0;i
//先发高字节,后发低字节 - {
- DTemp = Read_SPI_OneByte();
- drData = drData<<8;
- drData += DTemp;
- CheckSumR += DTemp;
- }
-
- CheckSumR = ~CheckSumR;//校验和算法: ADDR+CMD+DATA 单字节求和取反。
-
- if (CheckSumR != Read_SPI_OneByte())//比较校验和
- {
- drData = 0xFFFFFFFF;
- }
-
- SPI_CS_HIGH(); //关闭SPI传输
- HAL_Delay(2);
- return drData;
- }
- /**************************Write RN8302******************************/
- void Write_SPI(uint16_t Address, uint32_t dwData,uint8_t Date_len)
- {
- uint8_t i,CheckSumR, DTemp;
-
- SPI_CS_LOW(); //开启SPI传输
-
- DTemp = (uint8_t)(Address&0x00FF);//
- CheckSumR = DTemp;
- Write_SPI_OneByte(DTemp);//写地址
- DTemp = (((uint8_t)(Address >> 4)) & 0xf0)+0x80 ;
- CheckSumR += DTemp;
- Write_SPI_OneByte(DTemp);//写命令
-
-
- for (i =0 ;i < Date_len;i++)//先发高字节,后发低字节
- {
- DTemp = (uint8_t)(dwData>>(Date_len-1-i)*8);
- Write_SPI_OneByte(DTemp);//写命令
- CheckSumR += DTemp;
- }
-
- CheckSumR = ~CheckSumR;//校验和算法: ADDR+CMD+DATA 单字节求和取反。
-
- Write_SPI_OneByte(CheckSumR);//写命令
-
- SPI_CS_HIGH(); //结束传输
- HAL_Delay(2);
- }
-
- void ReadAmmeterData(void)
- {
- uint32_t temp = 0;
-
- temp = READ_SPI(DeviceID_CMD,DeviceID_BYTE);//芯片ID//supposed to be 0x00830200(hex)
- printf("Device_ID=%x(hex)\r\n",(int)temp);
- if(temp != 0x00830200) //读ID
- {
- printf("===================== \r\n");
- printf("Device_ID!=0x00830200 \r\n");
- printf("===================== \r\n");
- return;
- }
-
- temp = READ_SPI(SYSSR_CMD,SYSSR_BYTE);//系统状态
- printf("SYSSR=%x(hex)\r\n",(int)temp);
- HAL_Delay(1000);
-
- temp = READ_SPI(UC_CMD,UC_BYTE);//读取电压有效值
- printf(" UC 寄存器有效值=%8X\r\n",(int)temp);
- printf(" UC 引脚处有效值=%8.2f\r\n",(float)(temp/167772));
- printf(" UC 端口处有效值=%8.2f\r\n",(float)(temp/167772*1.76));
- }
《RN8302B 用户手册》的3.2.2 有效值寄存器 提到
1-4 类有效值是四字节寄存器,为 28 位( bit0-bit27 )有符号数,采用补码格式, bit27 为符号位, bit28-bit31 和 bit27 相同总为零。这四类有效值参数更新的周期为 250ms 。
4.2.2 标准电压电流和有功功率值计算 提到
U理论=INT[(Vu/800)*2^27]
其中U理论是连接到RN8302B引脚上的电压值,Vu是寄存器里的值(2^27/800=167772)
见本文《一、硬件电路》(1.76=220V/125mV=1.76)
在USER CODE BEGIN Includes下添加以下代码
- #include
- #include
-
- #include "rn8302b.h"
-
- uint8_t t=0;
在USER CODE BEGIN 3下添加以下代码
- ReadAmmeterData();
- HAL_Delay(3000);
- HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
- printf("%d\r\n",++t);
四、实验结果
全部代码与RN8302B的手册