//SPIFLASH 质量测试函数 static void SPIFLASH_Test(void) { uint32_t i; uint8_t test_buffer[SPIFLASH_TEST_SIZE]; SPI_FLASH_Read(test_buffer, SPIFLASH_TEST_ADDR, sizeof(test_buffer)); UART_printf("Read data form 0x%x:\r\n", SPIFLASH_TEST_ADDR); for(i = 0; i < SPIFLASH_TEST_SIZE; i++) { UART_printf("[%x]:0x%x ", i, test_buffer[i]); } //写入测试数据 for(i = 0; i < SPIFLASH_TEST_SIZE; i++) { test_buffer[i] = i; } UART_printf("\r\n"); //写入数据 SPI_FLASH_Write(test_buffer, SPIFLASH_TEST_ADDR, sizeof(test_buffer)); UART_printf("Write data completed\r\n"); memset(test_buffer, 0, sizeof(test_buffer)); SPI_FLASH_Read(test_buffer, SPIFLASH_TEST_ADDR, sizeof(test_buffer)); UART_printf("Read data form 0x%x:\r\n", SPIFLASH_TEST_ADDR); //打印数据 for(i = 0; i < SPIFLASH_TEST_SIZE; i++) { UART_printf("[%x]:0x%x ", i, test_buffer[i]); } }
/* *@功能:2字节用户编号+4字节RFID+6字节时间+1字节开锁结果,存入记录区 * * 每条长度为13字节 */ void save_rfid_result(void) //操作钥匙 { uint32_t record_addr; uint32_t Lock_number_addr; uint32_t total_row; uint8_t temp_Lock_number[4]; IWDG_Feed(); record_addr= SPI_FLASH_ReadWord(RECORD_POINT); //已存储的组数 SPI_FLASH_Write(User_Num,record_addr,2); //写查找到的授权的用户编号到记录中,如果没有找到则编号为零 SPI_FLASH_Write(Lock_number,record_addr+2,4); //写读到的RFID到记录中 read_time(); //读取实时时间,放到time_buff中 SPI_FLASH_Write(time_buff,record_addr+6,6); //写实时时间到time记录中 SPI_FLASH_Write(&unlock_result,record_addr+12,1); //写开锁结果到记录中 //for debug SPI_FLASH_Read(item,record_addr,13); UART1nSendChar(1,item,13); delay_ms(1000); record_addr=record_addr+RECORD_LEN; //每条授权RECORD_LEN=13字节 //更改授权用户信息指针的位置 SPI_FLASH_WriteWord(RECORD_POINT,record_addr); //for debug point=SPI_FLASH_ReadWord(RECORD_POINT); //RECORD_POINT=RECORD_START UART1SendwordHex(1, point); delay_ms(1000); //要区分宏地址里存放的内容到底是表示地址还是数据 total_row= SPI_FLASH_ReadWord(RECORD_ROW); total_row=total_row+1; //授权信息条数加一 SPI_FLASH_WriteWord(RECORD_ROW,total_row); //for debug row=SPI_FLASH_ReadWord(RECORD_ROW); UART1SendwordHex(1, row); delay_ms(1000); }
/* *@功能:检查读取到的锁码是否在授权文件当中 * * */ uint8_t check_lock_code(void) { uint8_t i,j,total_row; uint8_t known_lock_number[4]; uint32_t lock_number_addr,addr_end; uint8_t IN_AUTHOR_OFFSET=4; //RFID在一条授权中的偏移 addr_end= SPI_FLASH_ReadWord(AUTHOR_POINT); //在界面的采码功能里会改变采码指针的值 total_row=(addr_end-AUTHOR_START)/AUTHOR_LEN; // if(total_row==0) // { // UART1nSendChar(1,"没有授权文件",11); //如果total_row=0, // return 0; // } for(i=0;i<total_row;i++) // { lock_number_addr=AUTHOR_START+i*AUTHOR_LEN+IN_AUTHOR_OFFSET; SPI_FLASH_Read(known_lock_number,lock_number_addr,4); IWDG_Feed(); if(Lock_number[0]==known_lock_number[0]&&Lock_number[1]==known_lock_number[1]&&Lock_number[2]==known_lock_number[2]&&Lock_number[3]==known_lock_number[3]) { SPI_FLASH_Read(User_Num,lock_number_addr-4,2); //如果读到的RFID在授权中则记录下其用户编号 return 1; //读到了就返回1 } } User_Num[0]=0; User_Num[1]=0; return 0; }
/* *@功能:在空闲状态的几个任务 *1.检测是否有按键按下 *2.检测是否读到RFID *3.检测是否接受到串口传来的指令 *4.检测是否有USB连接到计算机上 *5.检测锂电池电压是否低电 共5个任务按各自的时间轴转动,基本上无冲突 */ void ST_Idle(void) { uint16_t ss_num=0; uint16_t power_num=0; uint16_t usb_bit; uint8_t key_r=KEYNO; uint8_t usb_r=0; uint8_t bt_r=0; uint8_t time_num=0; uint8_t p_c=0; uint8_t ss_flag=0; ResetKey(); //KeyNum是一个全局变量 //Init_KeyNumuber(); //Key_Num =KEYINIT //根据flsah中的信息,更改主菜单中的信息 SPI_FLASH_Read(HsMenu[1].Name,GROUP_INFORMATION,10); SPI_FLASH_Read(HsMenu[2].Name,KEY_INFORMATION,8); // //for debug // SPI_FLASH_Read(item,GROUP_INFORMATION,10); // UART1nSendChar(1,item,10); // delay_ms(1000); // //for dedug // SPI_FLASH_Read(item,KEY_INFORMATION,8); // UART1nSendChar(1,item,8); // delay_ms(1000); //for dedug // UART1nSendChar(1,HsMenu[1].Name,10); // delay_ms(1000); // UART1nSendChar(1,HsMenu[2].Name,8); // delay_ms(1000); OLED_Clear(); ShowMenuNoInverse(HsMenu); Main_Oled_Power(); Main_Oled_Time(); //Choose_MenuOp1(); //主界面显示 while(1) { // if(g_State!=ST_IDLE) // return; if(time_num==20) { Main_Oled_Time(); time_num=0; } ++time_num; delay_ms(50); //按键按下检测,如果有按键就按下就进入菜单操作 key_r =GetKey(); //判断是否有按键操作 if(ss_flag==0&&key_r==KEYNO) //超时关屏 { ss_num++; if(ss_num>=choosetime*6)//按下超过10秒钟 300/50=6 { OLED_Display_Off(); ss_flag=1; ss_num=0; } } if(ss_flag==1&&(key_r ==KEYCLEAR||key_r ==KEYSURE||key_r ==KEYDOWN||key_r == KEYUP)) { OLED_Display_On(); ss_flag=0; ResetKey(); key_r=KEYNO; } if(key_r !=KEYNO&&key_r !=KEYINIT) { //ResetKey(); //读完按键值后,将按键值复位 g_State =ST_LCDMENU; return; //按任意按键进入可选择菜单 } // //RFID检测 // nChar =Read_RfidData(2,Rfid_Buff,0xff); //非常重要的一点,是理解Trismit()的关键 // if(nChar >=3) // { // g_State =ST_KEY;return; //检测ID信息数据,如果读到了rfid数据,则将g_State置为st_key // } //检测上位机连接下位机命令,从菜单界面进入USB通信中 usb_r =UART1ReadFrm(1,g_Buff,MAX_BUFF); //USB串口1,g_Buff是一个全局变量;#define MAX_BUFF 520 if(usb_r==7&&g_Buff[0]==0xaa&&g_Buff[1]==0x75&&g_Buff[2]==0x0d&&g_Buff[3]==0x02&&g_Buff[4]==0x00&&g_Buff[5]==0x01&&g_Buff[6]==0xD1)//如果返回0x00就发下一条授权 { usb_bit=(USB_CHEAK&(GPIO_Pin_1))>>1; if(usb_bit==1) //USB插上 { bluetooth_uart_switch=0; pc_to_slave(); //上位机连接下位机的处理 g_State =ST_USB; //进入USB通信 return; } } bt_r =UART3ReadFrm(3,g_Buff,MAX_BUFF); //蓝牙串口2,g_Buff是一个全局变量;#define MAX_BUFF 520 if(bt_r==7&&g_Buff[0]==0xaa&&g_Buff[1]==0x75&&g_Buff[2]==0x0d&&g_Buff[3]==0x02&&g_Buff[4]==0x00&&g_Buff[5]==0x01&&g_Buff[6]==0xD1)//如果返回0x00就发下一条授权 { bluetooth_uart_switch=1; pc_to_slave(); //上位机连接下位机的处理;使用接受到的g_Buff // m_UB3; // m_UB3.RBuff; g_State =ST_USB; //进入USB通信 return; } usb_bit=(USB_CHEAK&(GPIO_Pin_1))>>1; if(usb_bit==1) //USB已经插上,即从蓝牙切换到USB bluetooth_uart_switch=0; //电池电量检测 power_num++; if( power_num==0x15) //0x15*20时Power_Cheak()才会返回有效值 { power_num =0; IWDG_Feed(); Main_Oled_Power(); //更新电池电量 p_c=Power_Cheak(); //此函数运行20次才返回有效值 if(p_c==4) //检测电池电压,如果电池电压过低,则进入关机模式,并进行提示 { // Main_Oled_Time(); // Main_Oled_Power(); OLED_Show_LowBattry(); //延时1s后关机 g_WaitTimeOut = 0; SetTimer(TIMER_TIMEOUT,100,Do_TimeOut,THREE_MIN); while( g_WaitTimeOut == 0 ) { IWDG_Feed(); } KillTimer(TIMER_TIMEOUT); Sys_Enter_Standby(); } } }
/******************************************************************************* * @函数名称 main * @函数说明 主函数 * @输入参数 无 * @输出参数 无 * @返回参数 无 *******************************************************************************/ int main(void) { uint8_t fuf=0; uint8_t fu_e=1; //固件更新使能 uint8_t i=0; uint8_t hui[32]= {0x04,0x04,0xF4,0x54,0x54,0x54,0x54,0xFF,0x54,0x54,0x54,0x54,0xF4,0x04,0x04,0x00, 0x40,0x30,0x01,0x01,0x39,0x41,0x41,0x45,0x59,0x41,0x41,0x71,0x01,0x08,0x30,0x00};/*"恵",0*/ SystemTick_Init(); NVIC_Configuration(); oled_control_Init(); OLED_ON; OLED_Init(); SPI_FLASH_Init(); //SPI接口初始化 FLASH_Unlock(); //STM32内部Flash 解锁 //LED_Configuration(); //配置按键 KEY_Configuration();//按钮对应的PB5脚初始化 IAP_Init(); //即串口1初始化,但是没有串口中断程序 buzzer_control_Init(); coil_control_Init(); // OLED_Clear(); // OLED_ShowUnite(24,2,"if updata"); // OLED_ShowUnite(28,4,"press OK"); // delay_ms(500); // while(i<5) // { // OLED_Clear(); // OLED_DrawBMP(32,2,48,4,hui); // OLED_ShowUnite(48,2," 科 "); // OLED_ShowUnite(32,4," 合 技"); // delay_ms(500); // // OLED_Clear(); // OLED_ShowUnite(32,2," 合 技"); // OLED_DrawBMP(32,4,48,6,hui); // OLED_ShowUnite(48,4," 科 "); // delay_ms(500); // // i++; // } // OLED_Clear(); // OLED_DrawBMP(32,2,48,4,hui); // OLED_ShowUnite(48,2,"合科技"); // delay_ms(800); //测试发送 // while(1) // { // Send_Byte(ACK); //收到上位机发送的第0帧之后发送ACK命令 // Send_Byte(CRC16); //接着再发送C,表示等待上位机发送数据帧 // } //按键是否按下 //if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5) == 0x00) /* 出厂时,下载程序的步骤: 1.下载字库 2.下载IAP 3.下载应用程序 */ //在下载字库时,先将FIRMWARE_UPGRADE_FLAG标志置为1,所以再下载IAP程序时会直接进入固件更新 SPI_FLASH_Read(&fuf,FIRMWARE_UPGRADE_FLAG,1); if(fuf==1) { OLED_Clear(); //OLED_ShowUnite(16,2,"固件更新中..."); OLED_ShowUnite(32,2,"to updata"); delay_ms(500); //假如按键按下 //执行IAP驱动程序更新Flash程序 SerialPutString("\r\n======================================================================"); SerialPutString("\r\n= (C) COPYRIGHT 2011 Lierda ="); SerialPutString("\r\n= ="); SerialPutString("\r\n= In-Application Programming Application (Version 1.0.0) ="); SerialPutString("\r\n= ="); SerialPutString("\r\n= By wuguoyan ="); SerialPutString("\r\n======================================================================"); SerialPutString("\r\n\r\n"); Main_Menu(); } //否则执行用户程序 else { /* 在程序里#define ApplicationAddress 0x8003000 ,*(__IO uint32_t*)ApplicationAddress) 即取0x8003000开始到0x8003003 的4个字节的值, 因为我们的应用程序APP中设置把 中断向 量表 放置在0x08003000 开始的位置;而中断向量表里第一个放的就是栈顶地址的值 也就是说,这句话即通过判断栈顶地址值是否正确(是否在0x2000 0000 - 0x 2000 2000之间) 来判断是否应用程序已经下载了,因为应用程序的启动文件刚开始就去初始化化栈空间, 如果栈顶值对了,说应用程已经下载了启动文件的初始化也执行了; */ //判断用户是否已经下载程序,因为正常情况下此地址是栈地址。 //若没有这一句的话,即使没有下载程序也会进入而导致跑飞。 //*(__IO uint32_t*)ApplicationAddress 与 __vector_table[0]是一样的 //__vector_table[0]是应用程序栈的顶 //X=*(__IO uint32_t*)ApplicationAddress //if (( X & 0x2FFE0000 ) == 0x20000000) //X只有在0x20000000与0x2001FFFF之间时,才可能有(X&0x2FFE0000) == 0x20000000成立 //即栈顶是不是在以0x20000000开始的128K的范围内,这里便是STM32的RAM区域 if (( ( *(__IO uint32_t*)ApplicationAddress ) & 0x2FFE0000 ) == 0x20000000) { // OLED_Clear(); // OLED_ShowUnite(4,2,"Execute Program"); // delay_ms(500); //SerialPutString("Execute Program\r\n\n"); //跳转至用户代码 JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4); Jump_To_Application = (pFunction) JumpAddress; //初始化用户程序的堆栈指针 __set_MSP(*(__IO uint32_t*) ApplicationAddress); Jump_To_Application(); //执行复位中断函数 } else { OLED_Clear(); OLED_ShowUnite(4,2,"no user Program"); delay_ms(500); SerialPutString("no user Program\r\n\n"); } } // OLED_Clear(); // OLED_ShowUnite(16,2,"please reboot"); // delay_ms(500); // // SerialPutString("please reboot\r\n\n"); // while (1) // { // } }