当前位置:首页 » 《关注互联网》 » 正文

【RISC-V MCU 创新应用】一种网络型单相智能电表_电机小子!的博客

13 人参与  2022年01月24日 12:17  分类 : 《关注互联网》  评论

点击全文阅读


基于RISC-V MCU为核心的智能电能表,及有人云物联网平台监控数据

  • 一、预想功能
  • 二、系统框架
  • 三、硬件介绍
  • 四、软件介绍
    • 1.主函数
    • 2.电能计量模块相关驱动函数
    • 3.以太网模块相关驱动函数
  • 五、有人云平台控制面板
  • 六、功能验证
    • 1.完整成品展示
    • 2.OLED 屏幕显示测试
    • 3.有人云平台测试
  • 七.演示视频

一、预想功能

基于32 位通用增强型 RISC-V MCU CH32V103开发板作为核心控制主板,通过接收和处理单相电能检测模块实时获取的单相数据,包括对电压、电流、有功功率、无功功率、电能、功率因数、二氧化碳含量、频率、芯片温度等相关数据进行计算和整理,同时驱动OLED 屏幕实时刷新显示单相电能数据,并将数据进行打包后通过串口向以太网模块发送数据包,以太网模块将数据包上传至云端,实现远距离在有人云平台对数据进行监控及上下发指令功能。

二、系统框架

在这里插入图片描述

三、硬件介绍

请添加图片描述
该智能电表硬件部分主要由RISC-V MCU CH32V103开发板、电能计模块、以太网模块、驱动模块、OLED 屏幕以及排插等器件组成。

RISC-V MCU CH32V103开发板:作为核心主板。负责对电能检测模块下发收集指令,以及对电能检测模块响应的数据进行处理,一方 面对接收的单相数据进行转换后驱动OLED 屏幕对相关数据进行显示,另一方面对单相数据进行重新打包并通过串口对以太网模块进行数据传输。

电能计模块:通过排插连接电器,并实时检测外接电器的单相数据。若接收主板发来的接收指令,则将检测到的数据上发到主板。

以太网模块:作为开发板与云端进行数据传输的媒介。当模块接收主板下发的数据包时,会将数据包通过路由器上传到云端,有人云平台通过对数据进行接收并显示到监控界面上,用户也可通过在有人云的监控界面对主板下发数据和指令。

驱动模块:按照主板指令驱动散热器开关以及转动的速度等。

OLED屏幕:显示相关数据。

排插:可外接电器,支持220V交流供电,接入排插的电器运行时的单相数据不断被电能检测模块进行收集。

四、软件介绍

1.主函数

int main(void)
{

	uint8_t OLED_Show_Change = 0;
	uint8_t OLED_Show_First_In = 0;

	DisableGlobalIRQ();
	board_init();           //务必保留,本函数用于初始化MPU 时钟 调试串口

	gpio_init(B2, GPO, 0, GPIO_PIN_CONFIG);           //GPIO初始化  PB2//外接LED2
	gpio_init(C0, GPO, 1, GPIO_PIN_CONFIG);           //GPIO初始化  PC0//外接KEY
	gpio_init(C1, GPO, 1, GPIO_PIN_CONFIG);           //GPIO初始化  PC1//外接LED1
	gpio_init(C3, GPO, 0, GPIO_PIN_CONFIG);
	gpio_init(C4, GPO, 0, GPIO_PIN_CONFIG);
	uart_init(UART_1, 4800, UART1_TX_A9, UART1_RX_A10);
	uart_init(UART_2, 115200, UART2_TX_A2, UART2_RX_A3);

	uart_rx_irq(UART_1, ENABLE);
//	uart_tx_irq(UART_1, ENABLE);
	uart_rx_irq(UART_2, ENABLE);
//  uart_tx_irq(UART_2, ENABLE);

	U_OLED_Init();  //用户初始化OLED函数
	U_OLED_Clear(); //清屏函数

	timer_pit_interrupt_ms(TIMER_1, 10);	//初始化定时TIM1  10毫秒中断一次
	EnableGlobalIRQ(0);

	while (1)
	{

		if (U_Tim_Count > 250)//计时
		{
			U_Tim_Count = 0;
			OLED_Show_Change++;

			if (OLED_Show_Change > 2)
			{
				OLED_Show_Change = 0;
				OLED_Show_First_In = 0;

			}
		}

		switch (OLED_Show_Change)//OLED切屏
		{
		case 0:

			U_Show_IM1253B_Data1(OLED_Show_First_In, U_IM1253B_Data);
			OLED_Show_First_In = 1;
			break;
		case 1:

			U_Show_IM1253B_Data2(OLED_Show_First_In, U_IM1253B_Data);
			OLED_Show_First_In = 0;
			break;
		case 2:

			U_Show_IM1253B_Data3(OLED_Show_First_In, U_IM1253B_Data);
			OLED_Show_First_In = 1;
			break;
		default:
			break;
		}
		if (MCU_Interrupt0_Timer_1S_End) //定时1S向IM1253B模块发送读取相关寄存器数据的命令
		{
			U_Send_RendCommand_IM1253B(); //向IM1253B模块发送读取相关寄存器数据函数
			MCU_Interrupt0_Timer_1S_End = 0;
			U_Send_Ethernet_Data();//向以太网模块发送电能数据
			systick_delay_ms(100);//延时100ms,分段发送数组
			U_Send_Ethernet_Data2();//向以太网模块发送开关数据
		}

		U_Calculation_IM1253B_Data(); //计算IM1253B相关电能数据函数

	    receive_key();//接收以太网下发数据


	}
}

2.电能计量模块相关驱动函数

串口1中断函数

void USART1_IRQHandler(void)
{

	static uint8_t U_GetData;

	uart_query(UART_1, &U_GetData);
	USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	U_MCU_UART1_GetData_End = U_Get_IM1253B_Data(U_GetData); //接收IM1253B电能计量模块驱动函数


}

读取电能计上发的数据,进行判断后存入特定数组中

uint8_t U_Get_IM1253B_Data(uint8_t Get_Data)
{
	static uint8_t i = 0;
	static uint8_t Get_Data_Buf[37] =
	{ 0 }; //存储获取数据数组

	Get_Data_Buf[i++] = Get_Data; //将获取到的数据存入数组
	if (Get_Data_Buf[0] != 0x01)  //判断帧头
	{
		i = 0;
	}
	if ((i == 2) && (Get_Data_Buf[1] != 0x03)) //判断帧头
	{
		i = 0;
	}
	if ((i == 3) && (Get_Data_Buf[2] != 0x20)) //判断帧头
	{
		i = 0;
	}

	if (i > 2)
	{
		if (i != (Get_Data_Buf[2] + 5))
		{
			return 0;
		}
		if (Get_Data_Buf[2] == 0X20)
		{
			memcpy(IM1253B_Data_Buf, Get_Data_Buf, 37); //将数据拷贝到IM1253B_Data_Buf数组中
			return 1;
		}
	}
	return 0;
}

向电能计发送读取相关寄存器命令函数

void U_Send_RendCommand_IM1253B(void)
{
	static uint8_t ReadCommad[8] =
	{ 0x01, 0x03, 0x00, 0x48, 0x00, 0x08, 0xc4, 0x1a }; //读取IM1253B相关寄存器命令
	uint8_t i = 0;
	for (i = 0; i < 8; i++)
	{
		uart_putchar(UART_1, ReadCommad[i]);
		systick_delay_ms(1);
	}
}

3.以太网模块相关驱动函数

对电能相关数据进行打包并发送给以太网模块函数

void U_Send_Ethernet_Data(void)//用户向以太网模块发送电能相关数据
{
	uint8_t U_Send_Ethernet_Data[45] =
	{ 0x01, 0x46, 0x00, 0x00, 0x00, 0x10, 0x20 };		//电能和温度数据存储数组
	Float_Data_Arry_Change_uchar(U_Send_Ethernet_Data, U_IM1253B_Data_Float,10);//浮点型16进制数据转化成字符型数据并存入电能和温度数据存储数组
	U_GetCrcData(U_Send_Ethernet_Data, 39);		//计算Modbus RTU协议的CRC校验码
	//systick_delay_ms(500);
	uart_putbuff(UART_2, U_Send_Ethernet_Data, 41);

}

向以太网发送设备开关指令函数


void U_Send_Ethernet_Data2(void)//发送开关指令
{

	uint8_t U_Send_Ethernet_Data2[12] =
	{ 0x01, 0x45, 0x00, 0x00, 0x00, 0x10, 0x02 };		//开关
	U_Send_Ethernet_Data2[7] = U_Ethernet_Data_Float[0];//将开关信号存入相关数组内
	U_Send_Ethernet_Data2[8] = U_Ethernet_Data_Float[1];

	U_GetCrcData(U_Send_Ethernet_Data2, 9);//计算校验位
	uart_putbuff(UART_2, U_Send_Ethernet_Data2, 11);//输出开关指令



}

对以太网模块返回到主板的数据进行判断后把特定数据存入数组中

uint8_t U_MCU_UART2_GetData_End = 0;  //串行口2接收数据结束标志位
uint8_t Ethernet_Data_Buf[8] =	{ 0 };
uint8_t U_Get_Ethernet_Data(uint8_t Get_Data)//接收以太网下发的数据并进行判断,存入数组中
{
	static uint8_t i = 0;
	static uint8_t E_Data_Buf[8] =
	{ 0 }; //存储获取数据数组

	E_Data_Buf[i++] = Get_Data; //将获取到的数据存入数组
	if (E_Data_Buf[0] != 0x01)  //判断帧头
	{
		i = 0;
	}
	if ((i == 2) && (E_Data_Buf[1] != 0x05)) //判断帧头
	{
		i = 0;
	}
	if ((i == 3) && (E_Data_Buf[2] != 0x00)) //判断帧头
	{
		i = 0;
	}
	if ((i == 4) && (E_Data_Buf[3] != 0x00)) //判断帧头
	{
		i = 0;
	}
	if(i == 8)//接收完一套完整的数据
	{
		memcpy(Ethernet_Data_Buf, E_Data_Buf, 9);将数据拷贝到Ethernet_Data_Buf数组中(比数组个数多一位,否则未知bug)
	}

}

计算校验位函数

static void U_GetCrcData(uint8_t *U_Data_Buffer, uint8_t len)//计算Modbus RTU协议的CRC校验码
{
	uint16_t wcrc = 0XFFFF;					//16位crc寄存器预置
	uint8_t temp;
	uint8_t CRC_L, CRC_H;
	uint8_t i = 0, j = 0;			//计数
	for (i = 0; i < len; i++)				//循环计算每个数据
	{
		temp = *U_Data_Buffer & 0X00FF;			//将八位数据与crc寄存器亦或
		U_Data_Buffer++;							//指针地址增加,指向下个数据
		wcrc ^= temp;						//将数据存入crc寄存器
		for (j = 0; j < 8; j++)				//循环计算数据的
		{
			if (wcrc & 0X0001)				//判断右移出的是不是1,如果是1则与多项式进行异或。
			{
				wcrc >>= 1;					//先将数据右移一位
				wcrc ^= 0XA001;				//与上面的多项式进行异或
			}
			else							//如果不是1,则直接移出
			{
				wcrc >>= 1;					//直接移出
			}
		}
	}
	CRC_L = wcrc & 0xff;							//crc的低八位
	*U_Data_Buffer = CRC_L;
	CRC_H = wcrc >> 8;							//crc的高八位
	*(U_Data_Buffer + 1) = CRC_H;
}

五、有人云平台控制面板

在这里插入图片描述
在有人云平台对控制界面进行编辑排版,定义相关变量及协议。

六、功能验证

1.完整成品展示

请添加图片描述

2.OLED 屏幕显示测试

将设备接入负载,打开电源。
请添加图片描述
如上所示,OLED 屏幕显示正常,且数据无错误。

3.有人云平台测试

接通电源和电器后在电脑端打开有人云平台请添加图片描述
如上所示,数据能够正常显示且实时更新。

打开手机有人云平台小程序
请添加图片描述
如上所示,数据能正常显示且实时更新。

正常状态下散热器未打开
请添加图片描述

打开下发指令开关
在这里插入图片描述
请添加图片描述
如上所示,可见散热器开始转动,云平台下发指令成功,开发板执行指令成功。

综合上面几项测试,以RISC-V MCU CH32V103芯片为核心的开发板实现了对电能数据的收发和处理以及通过OLED正常显示,对云平台实现数据交换以及远程无线指令上发下发和执行功能,达到预想功能,测试成功。

七.演示视频

演示视频


点击全文阅读


本文链接:http://zhangshiyu.com/post/33792.html

数据  电能  模块  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1