当前位置:   article > 正文

单片机设计基于STM32的燃气消费控制系统设计_stm32加气机

stm32加气机

概要

  本文主要是基于STM32微控制器为控制核心,以RC522射频模块和IC卡作为燃气计费的载体。该系统通过气体流量传感器实时监测燃气流量信息,把得到的数据传给微控制器,微控制器对气体流速积分运算得到的燃气量,然后根据燃气单价换算成金额后,更新IC卡内余额。并在OLED屏实时显示用户的余额信息。当余额低于阈值时,提示用户IC卡充值。当可用额度为零时,关断继电器,关闭燃气的供应,实现对燃气消费的自动控制。
经过调试后,系统可以对燃气消费量进行扣费,以及IC卡充值。并可以实时显示用户消费信息,同时可以根据卡内余额控制燃气关断和提醒用户提前充值。

关键字: STM32;燃气消费;流量计;RC522射频模块;OLED屏

一、本设计研究的内容和主要工作

  本设计研究的主要内容是基于STM32微控制器和IC卡实现对燃气消费系统的控制,实现对燃气消费系统的安全可靠,方便快捷控制。
  本设计的主要工作为:
  首先,查阅相关文献资料,了解燃气消费系统的研究背景和意义及国内外现状;
  其次,了解燃气消费系统的运行模式,确定需要控制的系统,明确相关生产规范,初步分析并设计子系统;
  再次,了解相关硬件并选定合适的系列,实现各个模块与微控制的焊接与连接,然后,根据逻辑顺序设计程序流程图和程序框架,熟练掌握嵌入式的编程方法,设计控制程序,完成相应的功能,然后进行系统调试工作。

二、总体方案设计

2.1 系统设计要求

  以燃气消费系统控制为对象,采用合适的嵌入式硬件和软件系统,设计并实现对燃气消费的自动控制。实现燃气流量的计费:并结合燃气单位价格计算燃价格,再通过读卡设备更新IC卡中的金额;流量控制:从读卡器中获得用户的插卡信息及IC卡内的金额信息,以判断是否开启或关闭控制阀门以及提醒用户充值后继续使用;信息提示:通过显示设备将IC卡的余额、燃气表状态及其他状态信息通过显示设备显示给用户,余额不足提醒用户充值。

2.2 方案论证

方案一:采用51单片机作为主控制芯片,51单片机结构经典、总线完善,而且具有位操作系统,操作起来也方便。对于轻量的控制系统来说,51单片机也是很好的选择。但是51单片机在运行速度方面相对较慢,外设资源较少,芯片保护机制不好,对于本设计的运行速度和后期系统升级都存在限制。
方案二:选择STM32F1系列处理器作为主控芯片,该系列单片机内核频率相对较高,运行内存和FLASH充足,运行速度快。而且外设资源丰富,且具备常用通信总线。可以完成本设计控制,而且方便后期系统升级。
方案三: 选用STM32F4系列芯片,该系列芯片属于高端处理器,系统频率高,运行内存大,性能强大,而且加入DSP图像处理和浮点型运算。但是本设计对于图像处理要求不高,而且这款芯片价格相对F1系列比较昂贵。
所以综合上诉三种方案,基于本设计对控制器的要求,从控制器处理性能、后期的系统升级、以及对芯片价格三个方面的综合考虑。选择STM32F1系列芯片作为本设计的主控芯片。

2.3 总体方案

  本设计采用STM32F103C8T6主控芯片对数据进行采集处理,通过CFA100流量检测燃气的流速,CFA100流量计的信号是模拟信号,单片机通过内部16位ADC,进行模数转换,然后计算出燃气的使用量,结合燃气单价,算出总消费额后,对M1的射频卡进行扣费。
  RC522与STM32主控芯片通过SPI进行通信,经过寻卡→防冲突→选卡→读取IC卡中的金额,根据用户使用的燃气流量计算出消费金额后扣除IC卡中的费用,当余额减到设定阈值时,蜂鸣器会报警一段时间,提醒用户燃气充值。当卡内金额减到0.0时,通过IO口控制外部继电器模块关断电磁阀切断燃气供应,并提醒用户IC卡充值。
  12864OLED屏与STM32主控芯片采用SPI通信,显示模块主要显示3个界面的芯片:一是用户没有插入IC卡时,消费控制系统的主界面,提示用户插卡消费燃气;二是用户插入IC后,显示用户的基本信息、账户余额、以及燃气使用总量,方便用户实时知道自己的卡内余额和燃气使用量,方便用户提前充值,避免突然切断燃气给消费用户带来的不便;三是余额低于设定阈值时,显示余额不足,提示用户提前进行燃气充值;四是燃气消费额为0.0时,显示余额为0.0,提醒用户充值。五是充值界面,显示用户余额,以及充值金额信息。
  继电器通过IO和主控芯片进行通信,主要用于根据用户的卡内余额,打开或者关闭燃气管道电磁阀。无源蜂鸣器模块主要是给用户提示信息,如果用户余额不足,会提起给予报警,提示用户提前充值,以避免给用户带来不便。
  根据上述硬件组成,基于STM32的燃气消费控制系统总体框图如图2.1所示。
在这里插入图片描述

图2.1 系统总体框图

三、系统硬件设计

3.1 单片机系统电路设计

3.1.1 电源电路设计

   嵌入式设计系统电源电路的设计肯定是必不可少,本设计中采用USB 5V供电,经过ASM117-3.3V稳压芯片输出3.3V电压,3.3v电压STM32F103C8T6,12864OLED屏幕、继电器、LED灯、蜂鸣器、射频卡模块以及流量传感器CAF100提供工作电压。
   该系统中还提供了两个5V和两个3.3V的扩展供电模块,以方便连接其他外设。电源电路如图3.1所示。
在这里插入图片描述

图3.1 电源电路

四、软件设计

4.1 软件设计的总体思路

本系统设计的功能如下:
1.开机后正常运行界面,在OLED屏会显示本设计系统的名字,并且下方有提示用户插入IC卡的提示图片。当用户插入有效IC卡后系统进入IC卡计费界面,屏幕会显示用户的楼层后以及卡内余额信息。
2.充值功能:本设计采用按键对IC卡进行模拟充值操作,当按下按键1时,进入充值界面,每按下一次设置的为充值10元。当按下按键2时,退出充值页面。
3.燃气检测和IC卡扣费功能:通过燃气流量计CFA100和和STM32内部的ADC检测当前燃气的状态,如果有气体流动,根据气体流速计算出气体的体积,进行扣费。
4.关断功能:当读卡器检测不到IC卡,继电器断开,断开燃气通道电磁阀,断开燃气的供应。当检测到IC卡余额不足时,继电器同样断开。
5.报警提醒功能:当检测到IC卡的钱数小于阈值时,会在OLED屏幕余额显示界面下方显示余额不足的界面。提示用户进行充值。
软件整体设计流程图如图4.1所示。

在这里插入图片描述

图4.1 软件整体设计流程图

每部分外设调试完成之后,就可以把各个外设统一起来,实现整体功能,如图整个系统处于开机没有IC卡插入,系统和开机界面相同,显示系统名字,以及提示用户插卡消费的提示简图。燃气关断状态的实物图如图5.7所示。
在这里插入图片描述

图5.7 燃气关断状态系统实物图
当有效IC卡插入,金额充足,OLED屏显示住户楼层信息、账户余额、以及消费的总气体量。继电器闭合,指示灯亮起,打开燃气阀,供应燃气。燃气处于供应状态的实物图如图5.8所示。
在这里插入图片描述

图5.8 燃气处于供应状态的体统实物图
当有效IC卡插入,金额小于设定阈值10.0但大于0.0时,蜂鸣器会报警一小段时间,提示用户余额不足。OLED屏显示住户楼层信息、账户余额不足提醒、以及消费的总气体量。继电器依然闭合,指示灯亮起继续供应燃气。余额低于设定阈值时的实物图如图5.9所示。
在这里插入图片描述

图 5.9 余额低于设定阈值的实物图
当有效IC卡插入,金额为0.0时时,蜂鸣器会报警一段时间,提示用户余额为零请充值。OLED屏显示住户楼层信息、余额不足0.0、余额不足请充值提醒。继电器断开,继电器断开指示灯熄灭,关闭燃气供应。卡内余额为0.0时的实物图如图5.10所示。
在这里插入图片描述

图5.10 卡内余额为0.0时的实物图
当用户充值IC卡时,本设计采用按键充值,每次按下充值10.0元,充值界面依然显示用户楼层信息、账户余额,以及充值的金额。IC卡充值界面如图5.11所示。
在这里插入图片描述

图5.11 IC卡充值界面

主要函数

主函数程序:
#include "main.h"
#include "main.h"

char oled_ic_new_value[16] ;
char oled_increment[16];
extern float oled_read_value;
extern float ic_old_value;
char disply_read_value[16];
char oled_sum_gas[16];
char user_name[16] ;
char oled_add[16];
float add_money = 0;
u8 lst_10 = 0;
u8 increment = 0;
u8 ui_2 = 0;
u8 ui_1 = 1;
u8 ui_0 = 1;
u8 BEEP_flag = 0;
u8 ui_0_clear = 0;
u8 ui_1_clear = 0;
u8 ui_2_clear = 0;
u8 BEEP_once = 0;
u8 BEEP_two = 0;
u8 beep_three = 0;
u32 beep_count = 0;
u8 gas_read_flag = 0;
int Increment_ret = 0;
int decrement_ret = 0;
extern float sum_gas ;
int main()
{
	Delay_Init();			//滴答定时器初始化
	Led_Config();			//LED灯初始化
	USART1_Config(115200);	//串口初始化
	Adc_Config();
	KEY_Config();
	ADC1_DMAConfig();
	char KEY = 0;
	printf("串口初始化成功\r\n");
	OLED_Init();
	RFIDGPIO_Config();
	ply_Config();
	Beep_Config_TIM3_CH4(7200,3000,0);
	while(1)
	{
		

		if(timekey[0]>timekey[1])
		{
			switch(Get_KeysValue())//KEY
			{
				case KEY1_PUSH :
					if(ui_2_clear == 0)
					{
						ui_0_clear = 0;
						ui_1_clear = 0;
						ui_2_clear = 1;
						OLED_Clear_once(0,127,0,7);
					}
					if(ui_2 == 1)
					{
						increment = 1;
					}
					ui_0 = 0;
					ui_1 = 0;
					ui_2 = 1;
				break;
				case KEY2_PUSH :
					 ui_2 = 0;
				     ui_1 = 1;
					 ui_0 = 0;
					add_money = 0;
					OLED_Clear_once(0,127,0,7);
				
				break;
				default : break;	
			}
				
		  timekey[0] = 0;
		}
		if(timeply[0] > timeply[1])
		{
			if(IC_Read_float(4) == MI_OK) 
			{
				BEEP_once = 1;
			}	
				
			if(ic_no_card_count<2 && ply_flag_value == 1)  //成功寻到卡余额大于0
			{
				printf("ply_flag == 1\r\n");
				OPEN_PLY;
			}
			else if(ic_no_card_count >2 || ply_flag_value ==0)  //超过2次没有寻到卡,或者余额不大于0
			{
				printf("ply_flag == 0\r\n");
				CLOSE_PLY;
			}
			if(ic_no_card_count >2)  //没有读到卡
			{
				if(ui_0_clear == 0)
				{
					ui_1_clear = 0;
					ui_2_clear = 0;
					ui_0_clear = 1;
					OLED_Clear_once(0,127,0,7);
				}
				ui_0 = 1;
				add_money = 0;
				BEEP_once = 0;
				BEEP_two = 0;
				beep_three =0;
				gas_read_flag = 0;
				beep_count = 0;
				BEEP_flag =0;  //为下次读到卡蜂鸣器滴一声做准备
			}
			else if(ic_no_card_count <= 2 && ui_2 == 0)  //显示余额
			{
				
				ui_1 = 1;
				ui_0 = 0;
				if(ui_1_clear == 0)
				{
					ui_0_clear = 0;
					ui_2_clear = 0;
					ui_1_clear = 1;
					OLED_Clear_once(0,127,0,7);
				}
				if(oled_read_value <= 10.0)
				{
					lst_10 = 1;
				}
				else 
				{
					lst_10 = 0;
				}
				
			}
			timeply[0] = 0;
		}
		if(timeadc[0]>timeadc[1]) //20ms检测一次
		{
			//ADC_Display();//ADC采样显示
			if(ply_flag_value == 1)
			{
				Amount_gas();	
			}
			timeadc[0] = 0;
		}
		if(timerc522[0] >timerc522[1])
		{
			if(increment == 1  )
			{
				Increment_ret = IC_Increment_float(4,10.0);//按一次充值10元
				if(Increment_ret == MI_OK  && ic_new_value >ic_old_value)
				{
					add_money = add_money +10;
					increment = 0;
				}
				
			}
			
			if(cost_flag == 1 && ply_flag_value == 1 && oled_read_value>0) //每次扣0.1元
			{
				decrement_ret = IC_Decrement_float(4,0.1);
				if(decrement_ret == MI_OK  && ic_new_value <ic_old_value)
				{
					cost_flag = 0;
					lst_10 = 0;
				}
				if(decrement_ret == 1 && ic_new_value <ic_old_value )
				{
					cost_flag = 0;
					lst_10 = 1;
				}
			}
			timerc522[0] = 0;
		}
		if(timeoled[0] > timeoled[1])
		{
			if(ui_0 == 1)
			{
				ui_1 = 0;
				ui_2 = 0;
				OLED_Show_chinese(16,0,0,6,OLED_ui_0);
				OLED_showphoto(32,2,gImage_ui_0,80,48);
			}
			if(ui_1 == 1)
			{
				ui_0 = 0;
				ui_2 = 0;
				OLED_Show_chinese(0,0,6,3,OLED_ui_0);
				OLED_ShowStr1(50,0,user_name);
				sprintf(disply_read_value,"%.1f",oled_read_value);
				OLED_ShowStr1(60,3,disply_read_value);	
				if( ply_flag_value == 0) //余额为零
				{
					beep_three = 1;
					OLED_ShowStr1(96,6,"      ");
					OLED_Show_chinese(0,3,12,4,OLED_ui_0);
					OLED_Show_chinese(0,6,17,7,OLED_ui_0);	
				}
				else if(lst_10 == 1)
				{
					BEEP_two = 1;
					OLED_Show_chinese(0,3,12,4,OLED_ui_0);
					OLED_Show_chinese(0,6,24,4,OLED_ui_0);
					sprintf(oled_sum_gas,"%.1f",sum_gas);
					OLED_ShowStr1(60,6,oled_sum_gas);
				}
				else
				{
					BEEP_two = 0;
					OLED_Show_chinese(0,3,0,4,OLED_IC);
					OLED_Show_chinese(0,6,24,4,OLED_ui_0);
					sprintf(oled_sum_gas,"%.1f",sum_gas);
					OLED_ShowStr1(60,6,oled_sum_gas);
				}
				
			}
			if(ui_2 == 1)
			{
				ui_0 = 0;
				ui_1 = 0;
				OLED_Show_chinese(0,0,6,3,OLED_ui_0);
				OLED_ShowStr1(50,0,user_name);
				OLED_Show_chinese(0,3,0,4,OLED_IC);
				sprintf(oled_increment,"%.1f",ic_new_value);
				OLED_ShowStr1(60,3,oled_increment);
				OLED_Show_chinese(0,5,9,3,OLED_ui_0);
				sprintf(oled_add,"%.1f",add_money);
				OLED_ShowStr1(60,5,oled_add);
			}
			timeoled[0] = 0;
		}
		if(timebeep[0]> timebeep[1])
		{
			if( BEEP_flag == 0 && BEEP_once == 1)//读卡成功,蜂鸣器滴一声
			{
				OPEN_beep(50);
				Delay_ms(50);				
				OPEN_beep(0); 
				BEEP_flag = 1;
			}
			if(BEEP_two == 1 && beep_count <300)
			{
				beep_count++;
				printf("beep_count=%d\r\n",beep_count);
				OPEN_beep(500);
			}
			else if(beep_three == 1 && beep_count<450)
			{
				beep_count++;
				OPEN_beep(300);
			}
			else 
			{
				OPEN_beep(0);
			}
			timebeep[0] = 0;
		}
		//指示灯
		if(timeled[0]>timeled[1])
		{
			//IC_Init_float(4,100.0);
			if(IC_Read_sum_gas(5) == 0 && gas_read_flag == 0)
			{
				gas_read_flag = 1;
			}
			if(gas_read_flag == 1)
			{
				IC_write_sum_gas(5);
				IC_Read_user_name(12);
			}
			LEDx_TOGGLE(LED0_PORT,LED0_PIN);
			printf("beep_count=%d\r\n",beep_count);
			timeled[0] = 0;
		}
}


定积分估算燃气体积函数:

#define ADV_0SCCM 0.33
#define ADV_300SCCM 2.44
float gas_q[2] = {0.0,0.0};
float adc_v = 0.0;    //adc采样的电压值的模拟量值
uint8_t flag_q = 1;  
#define Dx   20  //分成20ms,认为20ms内,变化非常小,为线性 
#define PRECISION  0.02  //允许误差
#define ADC_RANGE 300    //测量范围 单位毫升 cc
float sum_gas = 0.0;     //使用天然气体的总量
#define PRICE_GAS 25.6  // 每立方米2.56元,扩大1000倍,每升2.56元
float sum_price = 0.0 ; //价格总量
float sum_price_temp_remain = 0.0; //每消费0.01元扣费,后的余额
float sum_gas_temp = 0.0;          //保存扣费0.01元前气体量
uint8_t cost_flag = 0;             //每消费0.01元,刷新卡内余额标志位置1
//定积分估算燃气总量函数:
int Amount_gas()
{
	uint32_t i = 0;
	float dx_gas_q = 0.0;
	float sum_price_temp = 0.0;
	uint32_t lenth=sizeof(dma_adcbuff)/(sizeof(dma_adcbuff[0]));
	flag_q = !flag_q;
	if(DMA1->ISR & (1<<1))
	{
		DMA1->ISR |=(1<<1);
		for (i=0;i<lenth;i++)
		{
			printf("dma_adcbuff[%d]=%d\r\n",i,dma_adcbuff[i]);
			adc_v = dma_adcbuff[i] * 3.3/4096.0;
			if(adc_v -ADV_0SCCM < PRECISION || ADV_0SCCM- adc_v > (-PRECISION))
			{
				 adc_v = ADV_0SCCM;
			}
			gas_q[flag_q] = (adc_v-ADV_0SCCM) * 300/(ADV_300SCCM-ADV_0SCCM);
			if(gas_q[flag_q] < 0.0 || gas_q[flag_q] - 0 < PRECISION || 0- gas_q[flag_q] > (-PRECISION))
			{
				gas_q[flag_q] = 0.0;
			}
			//printf("gas_q[%d] = %.2f\r\n",flag_q,gas_q[flag_q]);
			printf("V = %.6f\r\n",adc_v);
			
		}
		dx_gas_q = ((gas_q[!flag_q]+gas_q[flag_q]) * Dx /(2*60*100) );
		if(dx_gas_q < 0.004 ) //如果变化小于精度,认为没有变化
		{
			dx_gas_q = 0.0;
		}
		sum_gas = sum_gas+ dx_gas_q; 
		sum_price = sum_gas*PRICE_GAS/1000; //sum_gas单位是毫升
		//每消费满0.01元时,才会刷新IC卡账户余额,减少IC卡的擦写次数
		sum_price_temp = ((sum_gas-sum_gas_temp)*PRICE_GAS )/1000 + sum_price_temp_remain;
		sum_price_temp_remain = 0.0; //sum_price_temp_remain 只需要加1次
		if(sum_price_temp >=0.01)
		{
			sum_gas_temp  = sum_gas;
			sum_price_temp = 0; 
			sum_price_temp_remain = sum_price_temp -0.01;
			cost_flag = 1;
		}
		//printf("sum_price = %.3f\r\n",sum_price);
		
	}
	return 0;
}


RC522读余额程序:
int IC_Read_float(u8 Block)
{
	int read_sta = 0;
	if(Request_Anticoll_Select(PICC_REQALL,Card_Type,Card_Buffer,Card_ID)==MI_OK)
	{ 
		if(RC522_AuthState(PICC_AUTHENT1A,Block,IC_Default_Key,Card_ID)==MI_OK ) 
		{
			//读一遍余额
			if(Card_PurseGet_Float(Block,&oled_read_value)==MI_OK)
			{
					ic_no_card_count = 0;  //成功读取,失败寻卡次数清零
				//	printf("读取金额:%f\r\n",oled_read_value);//加之前的读出来打印
				if(oled_read_value >0.1)
				{
					ply_flag_value = 1;//打开继电器
					read_sta = 0;
					goto p1;
				}
				else
				{
					ply_flag_value = 0;
					read_sta = 0;
					goto p1;
					
				}
				
			}
		}			
	}
	else
	{
		read_sta = -1;
		ic_no_card_count ++;
		if(ic_no_card_count>200)
		{
			ic_no_card_count = 10;
		}
		goto p1;
	}
	p1:
	return read_sta;
}


RC522充值函数程序:
int IC_Increment_float(u8 Block,float increment_valve)
{
	if(Request_Anticoll_Select(PICC_REQALL,Card_Type,Card_Buffer,Card_ID)==MI_OK)
	{ 
		if(RC522_AuthState(PICC_AUTHENT1A,Block,IC_Default_Key,Card_ID)==MI_OK ) 
		{
			//加之前读一遍余额
			if(Card_PurseGet_Float(Block,&ic_old_value)==MI_OK)
			{
				printf("ic_old_value = %f",ic_old_value);//加之前的读出来打印
				
				if(ic_old_value>1000000.0)//判断是否还能再加 
				{
					return -1;
				}
				printf("add-go\r\n");
				//加值  
				if(Card_PurseIncrement_Float(Block,increment_valve) == MI_OK)
				{
					if(Card_PurseGet_Float(Block,&ic_new_value) == MI_OK )
					{
						flag_v = !flag_v;
						ic_v[flag_v] = ic_new_value;
						//Printing(Data_Buffer,16);
//						printf("+_OK\r\n");
						printf("ic_new_value = %f",ic_new_value);
						return MI_OK;
					}
				}
			}
		}
	}
	return -1;	
}


RC522扣费函数程序:
int IC_Decrement_float(u8 Block,float decrement_valve)
{
	int ret = 0;
	Request_Anticoll_Select(PICC_REQALL,Card_Type,Card_Buffer,Card_ID);
	RC522_AuthState(PICC_AUTHENT1A,Block,IC_Default_Key,Card_ID);
	if(Request_Anticoll_Select(PICC_REQALL,Card_Type,Card_Buffer,Card_ID)==MI_OK)
	{
	 
		if(RC522_AuthState(PICC_AUTHENT1A,Block,IC_Default_Key,Card_ID)==MI_OK ) 
		{
			//减之前读一遍余额
			if(Card_PurseGet_Float(Block,&ic_old_value)==MI_OK)
			{
				printf("ic_value = %f\r\n",ic_old_value);;//加之前的读出来打印
				
				//加值  
				if(Card_PurseDecrement_Float(Block,decrement_valve) == MI_OK)
				{
					if(Card_PurseGet_Float(Block,&ic_new_value) == MI_OK)
					{
						printf("ic_value = %f",ic_new_value);
						if(ic_new_value <= 10.0)
						{
							ret = 1;
						}
						else if(ic_new_value < 0.00001)
						{
							return 2;
						}
						else
						{
							ret = MI_OK;
						}
					}
			
				}
				return  ret ;
			}
		}
	}	
	return -1;
}


OELD 清屏程序:
void OLED_Clear(uint8_t col_start,uint8_t col_end,uint8_t page_start,uint8_t page_end)
{
	uint8_t i;
	uint8_t j;
	write_i(0x20,OLED_CMD);//-SET Page Addressing Mode (0x00/0x01/0x02)
	write_i(0x00,OLED_CMD);//horizontal 模式 
	//set column address
	write_i(0x21,OLED_CMD);
	write_i(col_start,OLED_CMD);//  column start
	write_i(col_end,OLED_CMD); // column end
	//set page address 
	write_i(0x22,OLED_CMD); 
	write_i(page_start,OLED_CMD);// page start
	write_i(page_end,OLED_CMD);// page end
	
	for(i=0;i<8;i++)
	{
		for(j=0;j<128;j++)
		{
			write_i(0x0,OLED_DATA);
		}
	}
}
OLED 显示图片函数:
/*
col_start 开始列
page_start  开始页
*p  图片模首地址
wide 图片宽度
high  图片高度
*/
void OLED_showphoto(uint16_t col_start, uint16_t page_start, const uint8_t *p,uint8_t wide,uint8_t high)
{
	uint8_t i = 0;
	uint8_t j = 0;
	//设置为水平地址模式
	write_i(0x20,OLED_CMD);
	write_i(0x00,OLED_CMD);
	//设置开始列地址和列结束地址
	write_i(0x21,OLED_CMD);
	write_i(col_start,OLED_CMD);  //列开始地址
	write_i(col_start+wide-1,OLED_CMD);//列结束地址
	//设置开始页地址和页结束地址
	write_i(0x22,OLED_CMD);
	write_i(page_start,OLED_CMD);
	write_i(page_start+high/8-1,OLED_CMD);
	for(i=0;i<(high/8);i++)  
	{
		for(j=0;j<wide;j++)
		{
		//写数据
			write_i(*(p++),OLED_DATA);
		}			
	}
}

OLED屏显示汉字函数:

//X--列地址,Y--页地址    Z--第几个字开始显示 
void OLED_Show_chinese(uint16_t x, uint16_t y,uint16_t Z,uint16_t count,uint16_t (* OLED_array)[16])
{
	uint8_t i = 0;
	uint8_t j = 0;
	uint8_t k=0;
  
	for(k=0;k<count;k++)  
	{
		
		for(i=0;i<2;i++)
		{
			OLED_SetPos (x+16*k, y+i);
			for(j=0;j<16;j++)
			{
			//写数据
				write_i(OLED_array[Z+i+2*k][j],OLED_DATA);
			}	
		}
		

	}
}

OLED屏显示字符函数:
// x 字符横坐标
// y 字符纵坐标
// c 要显示的字符

void OLED_ShowChar(uint16_t x, uint16_t y, char c)
{
  uint8_t i = 0;
  uint8_t j = 0;
  uint16_t count = 0;
  
	for(i=0;i<2;i++)  
	{
		OLED_SetPos (x, y+i);   
		for(j=0;j<8;j++)
		{
			//写数据
			write_i(ascii_8_16[c - 32][count++],OLED_DATA);
			//{0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x0F,0x01,0x01,0x01},/*"+",11*/43
		}			
	}
}


OLED屏显示字符串函数:
// x 字符横坐标
// y 字符纵坐标
// str 显示字符串首地址

void OLED_ShowStr1(uint16_t x, uint16_t y, char * str)
{
  uint16_t i = 0;
  while (str[i] != '\0')
  {
    OLED_ShowChar(x+=8, y, str[i]);
    if (x > OLED_WIDTH - 8)
    {
      x = 0;
      y += 2;
    }
    if (y > OLED_HIGH - 2)
    {
      y = 0;
    }
    
    i++;
  }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609

五、结论

  本设计中是基于燃气的消费控制,第一点要做的就是对气体的体积测量,因为传感器传送的是实时的流速信息,而且流速一般也不是均匀的,因此这些数据采集后的数据处理算法便成为了我的工作,我查阅资料,在高等数学中微分在工程计算中得到启发,采用数学的定积分近似运算–梯形法对燃气的总体积进行计算,又一次实践体验了数学在实际工程中的应用。在OLED屏显示界面中,因为要进行几个页面的切换,所以都要进行清屏处理,但是如果每刷新一次屏幕都清屏一次,会出现刷屏的问题,后来我想到UCOSII操作系统里的向量集思想,在每个界面刷新设置一个标志位,只在每次界面切换的时候刷新一次屏幕,这样就解决了刷屏的问题。在射频卡模块的学习过程中,一开始对这个模块没有了解,无从下手,后来请教他人,自己也在网上找资料,了解整个模块的工作流程,以及IC卡信息存储原理,IC卡每个块的相同与区别,最终成功驱动射频模块工作。
  经过不断地努力探索与调试,最终设计实现通过STM32和射频模块的燃气消费的自动控制,收获良多。
  本设计要在实际应用中发挥作用,当然还有很多地方值得去探索和发掘,比如对IC卡内的余额信息安全问题值得进一步提升,对仪表出现故障问题能即使的给出警告信息排查。对进一步的研究探索,我想加入网络信息,将用户燃气消费信息,以及卡内余额信息,都通过网络传输到数据库中,这样既能统计用户的燃气使用量也能增加消费者卡内信息安全。总体来说通过本次设计我收获的不仅仅是对专业知识的进一步学习,更学到了解决问题的办法,以及综合的理论实践能力。

六、 文章目录

目 录

目 录
1 绪论 1
1.1 研究的目的及意义 1
1.2 发展现状 1
1.3 本设计研究的内容和主要工作 2
2 总体方案设计 4
2.1 系统设计要求 4
2.2 方案论证 4
2.3 总体方案 4
3 系统硬件设计 6
3.1 单片机系统电路设计 6
3.2 系统显示模块 8
3.3 射频模块 10
3.4 流量计模块 12
3.5 继电器模块 13
3.6 按键模块 14
4 软件设计 15
4.1 软件设计的总体思路 15
4.2 定时器程序初始化 17
4.3 流量传感器程序设计 17
4.4 显示模块程序设计 18
4.5 射频卡模块程序设计 19
4.6 继电器、蜂鸣器和按键程序设计 24
5 系统调试与结果 27
5.1 各个模块的调试结果显示 27
5.2 整个系统调试结果显示 30
结 论 34
致 谢 35
参考文献 36
附录A 系统整体原理图 37
附录B 主要程序 38

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/233454
推荐阅读
相关标签
  

闽ICP备14008679号