IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 【RISC-V MCU 创新应用】一种网络型单相智能电表 -> 正文阅读

[嵌入式]【RISC-V MCU 创新应用】一种网络型单相智能电表

一、预想功能

基于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正常显示,对云平台实现数据交换以及远程无线指令上发下发和执行功能,达到预想功能,测试成功。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-26 10:20:39  更:2021-09-26 10:21:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 3:36:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码