赞
踩
本文主要是基于STM32微控制器为控制核心,以RC522射频模块和IC卡作为燃气计费的载体。该系统通过气体流量传感器实时监测燃气流量信息,把得到的数据传给微控制器,微控制器对气体流速积分运算得到的燃气量,然后根据燃气单价换算成金额后,更新IC卡内余额。并在OLED屏实时显示用户的余额信息。当余额低于阈值时,提示用户IC卡充值。当可用额度为零时,关断继电器,关闭燃气的供应,实现对燃气消费的自动控制。
经过调试后,系统可以对燃气消费量进行扣费,以及IC卡充值。并可以实时显示用户消费信息,同时可以根据卡内余额控制燃气关断和提醒用户提前充值。
关键字: STM32;燃气消费;流量计;RC522射频模块;OLED屏
本设计研究的主要内容是基于STM32微控制器和IC卡实现对燃气消费系统的控制,实现对燃气消费系统的安全可靠,方便快捷控制。
本设计的主要工作为:
首先,查阅相关文献资料,了解燃气消费系统的研究背景和意义及国内外现状;
其次,了解燃气消费系统的运行模式,确定需要控制的系统,明确相关生产规范,初步分析并设计子系统;
再次,了解相关硬件并选定合适的系列,实现各个模块与微控制的焊接与连接,然后,根据逻辑顺序设计程序流程图和程序框架,熟练掌握嵌入式的编程方法,设计控制程序,完成相应的功能,然后进行系统调试工作。
以燃气消费系统控制为对象,采用合适的嵌入式硬件和软件系统,设计并实现对燃气消费的自动控制。实现燃气流量的计费:并结合燃气单位价格计算燃价格,再通过读卡设备更新IC卡中的金额;流量控制:从读卡器中获得用户的插卡信息及IC卡内的金额信息,以判断是否开启或关闭控制阀门以及提醒用户充值后继续使用;信息提示:通过显示设备将IC卡的余额、燃气表状态及其他状态信息通过显示设备显示给用户,余额不足提醒用户充值。
方案一:采用51单片机作为主控制芯片,51单片机结构经典、总线完善,而且具有位操作系统,操作起来也方便。对于轻量的控制系统来说,51单片机也是很好的选择。但是51单片机在运行速度方面相对较慢,外设资源较少,芯片保护机制不好,对于本设计的运行速度和后期系统升级都存在限制。
方案二:选择STM32F1系列处理器作为主控芯片,该系列单片机内核频率相对较高,运行内存和FLASH充足,运行速度快。而且外设资源丰富,且具备常用通信总线。可以完成本设计控制,而且方便后期系统升级。
方案三: 选用STM32F4系列芯片,该系列芯片属于高端处理器,系统频率高,运行内存大,性能强大,而且加入DSP图像处理和浮点型运算。但是本设计对于图像处理要求不高,而且这款芯片价格相对F1系列比较昂贵。
所以综合上诉三种方案,基于本设计对控制器的要求,从控制器处理性能、后期的系统升级、以及对芯片价格三个方面的综合考虑。选择STM32F1系列芯片作为本设计的主控芯片。
本设计采用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 系统总体框图
嵌入式设计系统电源电路的设计肯定是必不可少,本设计中采用USB 5V供电,经过ASM117-3.3V稳压芯片输出3.3V电压,3.3v电压STM32F103C8T6,12864OLED屏幕、继电器、LED灯、蜂鸣器、射频卡模块以及流量传感器CAF100提供工作电压。
该系统中还提供了两个5V和两个3.3V的扩展供电模块,以方便连接其他外设。电源电路如图3.1所示。
图3.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++; } }
本设计中是基于燃气的消费控制,第一点要做的就是对气体的体积测量,因为传感器传送的是实时的流速信息,而且流速一般也不是均匀的,因此这些数据采集后的数据处理算法便成为了我的工作,我查阅资料,在高等数学中微分在工程计算中得到启发,采用数学的定积分近似运算–梯形法对燃气的总体积进行计算,又一次实践体验了数学在实际工程中的应用。在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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。