行業(yè)門戶網(wǎng)站建設(shè)方案書網(wǎng)絡(luò)營銷推廣8種方法
基于STM32人臉識別系統(tǒng)
(程序+設(shè)計報告)
功能介紹
具體功能:
可以實現(xiàn)進入頁面的設(shè)定自定義DIY;可以自由的添加需要識別的人臉;人臉靠近,按下識別按鍵可以實現(xiàn)人臉識別。如果在系統(tǒng)庫中會提示是那個人,如果不在會提示不在庫中。
程序
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "key.h"
#include "usmart.h"
#include "sram.h"
#include "malloc.h"
#include "w25qxx.h"
#include "sdio_sdcard.h"
#include "ff.h"
#include "exfuns.h"
#include "fontupd.h"
#include "text.h"
#include "piclib.h"
#include "string.h"
#include "math.h"
#include "dcmi.h"
#include "ov2640.h"
#include "beep.h"
#include "timer.h"
#include "atk_frec.h"int reg_time;
u8 ov2640_mode=0; //工作模式:0,RGB565模式;1,JPEG模式//得到path路徑下,目標文件的總個數(shù)
//path:路徑
//返回值:總有效文件數(shù)
u16 pic_get_tnum(u8 *path)
{ u8 res;u16 rval=0;DIR tdir; //臨時目錄FILINFO tfileinfo; //臨時文件信息 u8 *fn; res=f_opendir(&tdir,(const TCHAR*)path); //打開目錄tfileinfo.lfsize=_MAX_LFN*2+1; //長文件名最大長度tfileinfo.lfname=mymalloc(SRAMIN,tfileinfo.lfsize);//為長文件緩存區(qū)分配內(nèi)存if(res==FR_OK&&tfileinfo.lfname!=NULL){while(1)//查詢總的有效文件數(shù){res=f_readdir(&tdir,&tfileinfo); //讀取目錄下的一個文件if(res!=FR_OK||tfileinfo.fname[0]==0)break; //錯誤了/到末尾了,退出 fn=(u8*)(*tfileinfo.lfname?tfileinfo.lfname:tfileinfo.fname); res=f_typetell(fn); if((res&0XF0)==0X50)//取高四位,看看是不是圖片文件 {rval++;//有效文件數(shù)增加1} } } return rval;
}//處理JPEG數(shù)據(jù)
//當采集完一幀JPEG數(shù)據(jù)后,調(diào)用此函數(shù),切換JPEG BUF.開始下一幀采集.
void jpeg_data_process(void)
{ if(ov2640_mode)//只有在JPEG格式下,才需要做處理.{ }
}
//切換為OV2640模式
void sw_ov2640_mode(void)
{OV2640_PWDN=0;//OV2640 Power Up//GPIOC8/9/11切換為 DCMI接口GPIO_AF_Set(GPIOC,8,13); //PC8,AF13 DCMI_D2GPIO_AF_Set(GPIOC,9,13); //PC9,AF13 DCMI_D3GPIO_AF_Set(GPIOC,11,13); //PC11,AF13 DCMI_D4
}
//切換為SD卡模式
void sw_sdcard_mode(void)
{OV2640_PWDN=1;//OV2640 Power Down //GPIOC8/9/11切換為 SDIO接口GPIO_AF_Set(GPIOC,8,12); //PC8,AF12GPIO_AF_Set(GPIOC,9,12); //PC9,AF12 GPIO_AF_Set(GPIOC,11,12); //PC11,AF12
} //
//LCD顯示區(qū)域限制參數(shù)
u16 face_offx,face_offy;
u16 face_xsize,face_ysize; u8 fontsize=12; //字體大小//設(shè)置圖像到屏幕最中心.
void set_image_center(void)
{face_offx=0;face_offy=0;face_xsize=lcddev.width;face_ysize=lcddev.height;if(lcddev.id==0X1963||lcddev.id==0X5510){ face_offy=80;face_ysize=640;fontsize=24;}else if(lcddev.id==0X5310){face_offx=10;face_offy=40;face_xsize=300;face_ysize=400;fontsize=16;}else fontsize=12;LCD_Set_Window(face_offx,face_offy,face_xsize,face_ysize); //設(shè)置開窗口.
}//讀取原始圖片數(shù)據(jù)
//dbuf:數(shù)據(jù)緩存區(qū)
//xoff,yoff:要讀取的圖像區(qū)域起始坐標
//xsize:要讀取的圖像區(qū)域?qū)挾?//width:要讀取的寬度(寬高比恒為3:4)
void frec_get_image_data(u16 *dbuf,u16 xoff,u16 yoff,u16 xsize,u16 width)
{int w, h; u16 height=width*4/3;float scale=(float)xsize/width;for(h=0;h<height;h++){for(w=0;w<width;w++){dbuf[h*width+w]=LCD_ReadPoint(xoff+w*scale,yoff+h*scale); }}
}
//加載一個簡單界面
//fsize:字體大小
void frec_load_ui(u8 fsize)
{if(fsize==16){ Show_Str(10,2,310,fsize, " WK_UP:添加人臉模板",fsize,1); Show_Str(10,4+16,310,fsize," KEY2:刪除所有模板 KEY0:開始識別",fsize,1); }else if(fsize==24){ Show_Str(10,10,470,fsize, " WK_UP:添加人臉模板",fsize,1); Show_Str(10,20+24,470,fsize," KEY2:刪除所有模板 KEY0:開始識別",fsize,1); }
}
//顯示提示信息
//str:要顯示的字符串
//line:第幾行;0,第一行;1,第二行;其他,非法.
//fsize:字體大小
void frec_show_msg(u8* str,u8 line)
{if(line>1)return;if(lcddev.width==240){ Show_Str(10,lcddev.height-(2-line)*fontsize-(2-line)*5,lcddev.width,fontsize,str,fontsize,0);}else{Show_Str(10,lcddev.height-(2-line)*fontsize-(2-line)*(face_offy-fontsize*2)/3,lcddev.width,fontsize,str,fontsize,1); }
} u16 * pixdatabuf; //圖像緩存int main(void)
{ u8 res; u8 key; //鍵值 u8 key_first;u8 i; u8 msgbuf[30]; //消息緩存區(qū) u8 person;
//***********初始化界面相關(guān)的顯示變量**********//DIR picdir; //圖片目錄FILINFO picfileinfo;//文件信息u8 *fn; //長文件名u8 *pname; //帶路徑的文件名u16 totpicnum; //圖片文件總數(shù)u16 curindex; //圖片當前索引u8 pause=0; //暫停標記u8 t;u16 temp;u16 *picindextbl; //圖片索引表 Stm32_Clock_Init(336,8,2,7);//設(shè)置時鐘,168Mhz delay_init(168); //延時初始化 uart_init(84,115200); //初始化串口波特率為115200 LED_Init(); //初始化LED usmart_dev.init(84); //初始化USMARTTIM3_Int_Init(100-1,8400-1);//10Khz計數(shù),10ms中斷一次LCD_Init(); //LCD初始化 FSMC_SRAM_Init(); //初始化外部SRAM.BEEP_Init(); //蜂鳴器初始化KEY_Init(); //按鍵初始化 W25QXX_Init(); //初始化W25Q128 my_mem_init(SRAMIN); //初始化內(nèi)部內(nèi)存池 my_mem_init(SRAMEX); //初始化內(nèi)部內(nèi)存池 my_mem_init(SRAMCCM); //初始化CCM內(nèi)存池 exfuns_init(); //為fatfs相關(guān)變量申請內(nèi)存 f_mount(fs[0],"0:",1); //掛載SD卡 f_mount(fs[1],"1:",1); //掛載SPI FLASHPOINT_COLOR=RED; while(font_init()) //檢查字庫{ LCD_ShowString(30,50,200,16,16,"Font Error!");delay_ms(200); LCD_Fill(30,50,240,66,WHITE);//清除顯示 delay_ms(200); }while(f_opendir(&picdir,"0:/PICTURE"))//打開圖片文件夾{ Show_Str(30,170,240,16,"PICTURE文件夾錯誤!",16,0);Show_Str(30,190,240,16,"原因可能是SD卡沒有插好",16,0);delay_ms(200); LCD_Fill(30,170,240,186,WHITE);//清除顯示 delay_ms(200); } totpicnum=pic_get_tnum("0:/PICTURE"); //得到總有效文件數(shù)while(totpicnum==NULL)//圖片文件為0 { Show_Str(30,170,240,16,"沒有圖片文件!",16,0);delay_ms(200); LCD_Fill(30,170,240,186,WHITE);//清除顯示 delay_ms(200); }picfileinfo.lfsize=_MAX_LFN*2+1; //長文件名最大長度picfileinfo.lfname=mymalloc(SRAMIN,picfileinfo.lfsize); //為長文件緩存區(qū)分配內(nèi)存pname=mymalloc(SRAMIN,picfileinfo.lfsize); //為帶路徑的文件名分配內(nèi)存picindextbl=mymalloc(SRAMIN,2*totpicnum); //申請2*totpicnum個字節(jié)的內(nèi)存,用于存放圖片索引while(picfileinfo.lfname==NULL||pname==NULL||picindextbl==NULL)//內(nèi)存分配出錯{ Show_Str(30,170,240,16,"內(nèi)存分配失敗!",16,0);delay_ms(200); LCD_Fill(30,170,240,186,WHITE);//清除顯示 delay_ms(200); }//記錄索引res=f_opendir(&picdir,"0:/PICTURE"); //打開目錄if(res==FR_OK){curindex=0;//當前索引為0while(1)//全部查詢一遍{temp=picdir.index; //記錄當前indexres=f_readdir(&picdir,&picfileinfo); //讀取目錄下的一個文件if(res!=FR_OK||picfileinfo.fname[0]==0)break; //錯誤了/到末尾了,退出 fn=(u8*)(*picfileinfo.lfname?picfileinfo.lfname:picfileinfo.fname); res=f_typetell(fn); if((res&0XF0)==0X50)//取高四位,看看是不是圖片文件 {picindextbl[curindex]=temp;//記錄索引curindex++;} } } delay_ms(100);piclib_init(); //初始化畫圖 curindex=0; //從0開始顯示res=f_opendir(&picdir,(const TCHAR*)"0:/PICTURE"); //打開目錄if(res==FR_OK)//打開成功{ dir_sdi(&picdir,picindextbl[curindex]); //改變當前目錄索引 res=f_readdir(&picdir,&picfileinfo); //讀取目錄下的一個文件fn=(u8*)(*picfileinfo.lfname?picfileinfo.lfname:picfileinfo.fname); strcpy((char*)pname,"0:/PICTURE/"); //復(fù)制路徑(目錄)strcat((char*)pname,(const char*)fn); //將文件名接在后面LCD_Clear(BLACK);ai_load_picfile(pname,0,0,lcddev.width,lcddev.height,1);//顯示圖片 res = 0; }delay_ms(1000); myfree(SRAMIN,picfileinfo.lfname); //釋放內(nèi)存 myfree(SRAMIN,pname); //釋放內(nèi)存 myfree(SRAMIN,picindextbl); //釋放內(nèi)存 Show_Str(170,700,240,24,"Init....",24,1);LCD_Fill(170,700,240,24,BLACK); //填充單色key_first = 0;while(SD_Init())//檢查SD卡{ Show_Str(30,190,240,16,"SD Card Error!",16,0);delay_ms(200);LCD_Fill(30,190,239,206,WHITE);delay_ms(200); } while(OV2640_Init())//初始化OV2640{Show_Str(30,190,240,16,"OV2640 錯誤!",16,0);delay_ms(200);LCD_Fill(30,190,239,206,WHITE);delay_ms(200);}pixdatabuf=mymalloc(SRAMIN,ATK_GABOR_IMG_WID*ATK_GABOR_IMG_HEI*2); //申請內(nèi)存delay_ms(10);OV2640_RGB565_Mode(); //RGB565輸出OV2640_ImageWin_Set((1600-900)/2,0,900,1200);//設(shè)置輸出尺寸為:900*1200,3:4比例DCMI_Init(); //DCMI配置DCMI_DMA_Init((u32)&LCD->LCD_RAM,0,1,1,0);//DCMI DMA配置Show_Str(170,700,240,24,"Init Sucess!",24,1);LCD_Fill(170,700,240,24,BLACK); //填充單色delay_ms(300); Show_Str(170,730,240,24,"按任意鍵進入",24,1);LCD_Fill(170,730,240,24,BLACK); //填充單色while(key_first==0) {key_first = KEY_Scan(0);//不支持連按delay_ms(10); }LCD_Clear(BLACK);set_image_center(); //設(shè)置到屏幕正中央frec_load_ui(fontsize); //顯示GUI OV2640_OutSize_Set(face_xsize,face_ysize); sw_sdcard_mode(); //SD卡模式 res=atk_frec_initialization(); //初始化人臉識別if(res){printf("atk_frec_initialization error:%d\r\n",res);//打印錯誤代碼} sw_ov2640_mode(); //2640模式DCMI_Start(); //啟動傳輸 while(1){ delay_ms(10);key=KEY_Scan(0);//不支持連按if(key){DCMI_Stop(); //停止傳輸 sw_sdcard_mode(); //SD卡模式switch(key){case KEY2_PRES: //刪除所有模板sprintf((char*)msgbuf,"正在刪除...");frec_show_msg(msgbuf,0); for(i=0;i<MAX_LEBEL_NUM;i++){res=atk_frec_delete_data(i);//刪除模板if(res==FR_OK)printf("delete face:%d ok\r\n",i);else printf("delete face:%d failed\r\n",i);} atk_frec_load_data_model(); //重新加載所有識別模型(被刪掉的,將無法加載進來.)if(lcddev.width!=240)LCD_Fill(10,lcddev.height-2*fontsize-2*(face_offy-fontsize*2)/3,lcddev.width,lcddev.height,BLACK); //清除之前的顯示sprintf((char*)msgbuf,"刪除完成");frec_show_msg(msgbuf,0); delay_ms(1000);if(lcddev.width!=240)LCD_Fill(10,lcddev.height-2*fontsize-2*(face_offy-fontsize*2)/3,lcddev.width,lcddev.height,BLACK); //清除顯示break;case KEY0_PRES: //識別人臉frec_get_image_data(pixdatabuf,face_offx,face_offy,face_xsize,30);//讀取圖像數(shù)據(jù) sprintf((char*)msgbuf,"正在識別...");frec_show_msg(msgbuf,0); reg_time=0; res=atk_frec_recognition_face(pixdatabuf,&person);//進行識別if(res==ATK_FREC_MODEL_DATA_ERR){ sprintf((char*)msgbuf,"沒有可用模板,按KEY_UP添加模板!");}else if(res==ATK_FREC_UNREC_FACE_ERR){ sprintf((char*)msgbuf,"無法識別該人臉,請重試!"); }else {sprintf((char*)msgbuf,"識別結(jié)果:%02d號 耗時:%dms",person,reg_time*10); }if(lcddev.width!=240)LCD_Fill(10,lcddev.height-2*fontsize-2*(face_offy-fontsize*2)/3,lcddev.width,lcddev.height,BLACK); //清除之前的顯示frec_show_msg(msgbuf,0); sprintf((char*)msgbuf,"按任意按鍵繼續(xù)!"); frec_show_msg(msgbuf,1); while(!KEY_Scan(0)) //等待按鍵輸入{delay_ms(10); }if(lcddev.width!=240)LCD_Fill(10,lcddev.height-2*fontsize-2*(face_offy-fontsize*2)/3,lcddev.width,lcddev.height,BLACK);break;case WKUP_PRES://添加一個人像進入數(shù)據(jù)庫frec_get_image_data(pixdatabuf,face_offx,face_offy,face_xsize,30);//讀取圖像數(shù)據(jù)sprintf((char*)msgbuf,"正在添加人臉模板...");frec_show_msg(msgbuf,0); res=atk_frec_add_a_face(pixdatabuf,&person); //添加一個人臉if(res==0){sprintf((char*)msgbuf,"添加成功,編號:%02d ",person);atk_frec_load_data_model(); //重新加載所有識別模型(將添加的人臉,加載進來)}else {sprintf((char*)msgbuf,"添加失敗,錯誤代碼:%02d",res);}frec_show_msg(msgbuf,1); delay_ms(1000);if(lcddev.width!=240)LCD_Fill(10,lcddev.height-2*fontsize-2*(face_offy-fontsize*2)/3,lcddev.width,lcddev.height,BLACK);break; default :break;} sw_ov2640_mode(); //2640模式DCMI_Start(); //啟動傳輸 }delay_ms(10);i++;if(i==20)//DS0閃爍.{i=0;LED0=!LED0;}}
}#include "delay.h"
#include "sys.h"
//
//如果使用OS,則包括下面的頭文件(以ucos為例)即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h" //支持OS時,使用
#endif
//
****//完整資料
*//***微信公眾號:木子單片機****/
//All rights reserved
//********************************************************************************
//修改說明
//V1.1 20140803
//1,delay_us,添加參數(shù)等于0判斷,如果參數(shù)等于0,則直接退出.
//2,修改ucosii下,delay_ms函數(shù),加入OSLockNesting的判斷,在進入中斷后,也可以準確延時.
//V1.2 20150411
//修改OS支持方式,以支持任意OS(不限于UCOSII和UCOSIII,理論上任意OS都可以支持)
//添加:delay_osrunning/delay_ostickspersec/delay_osintnesting三個宏定義
//添加:delay_osschedlock/delay_osschedunlock/delay_ostimedly三個函數(shù)
//V1.3 20150521
//修正UCOSIII支持時的2個bug:
//delay_tickspersec改為:delay_ostickspersec
//delay_intnesting改為:delay_osintnesting
// static u8 fac_us=0; //us延時倍乘數(shù)
static u16 fac_ms=0; //ms延時倍乘數(shù),在os下,代表每個節(jié)拍的ms數(shù)#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS定義了,說明要支持OS了(不限于UCOS).
//當delay_us/delay_ms需要支持OS的時候需要三個與OS相關(guān)的宏定義和函數(shù)來支持
//首先是3個宏定義:
// delay_osrunning:用于表示OS當前是否正在運行,以決定是否可以使用相關(guān)函數(shù)
//delay_ostickspersec:用于表示OS設(shè)定的時鐘節(jié)拍,delay_init將根據(jù)這個參數(shù)來初始哈systick
// delay_osintnesting:用于表示OS中斷嵌套級別,因為中斷里面不可以調(diào)度,delay_ms使用該參數(shù)來決定如何運行
//然后是3個函數(shù):
// delay_osschedlock:用于鎖定OS任務(wù)調(diào)度,禁止調(diào)度
//delay_osschedunlock:用于解鎖OS任務(wù)調(diào)度,重新開啟調(diào)度
// delay_ostimedly:用于OS延時,可以引起任務(wù)調(diào)度.//本例程僅作UCOSII和UCOSIII的支持,其他OS,請自行參考著移植
//支持UCOSII
#ifdef OS_CRITICAL_METHOD //OS_CRITICAL_METHOD定義了,說明要支持UCOSII
#define delay_osrunning OSRunning //OS是否運行標記,0,不運行;1,在運行
#define delay_ostickspersec OS_TICKS_PER_SEC //OS時鐘節(jié)拍,即每秒調(diào)度次數(shù)
#define delay_osintnesting OSIntNesting //中斷嵌套級別,即中斷嵌套次數(shù)
#endif//支持UCOSIII
#ifdef CPU_CFG_CRITICAL_METHOD //CPU_CFG_CRITICAL_METHOD定義了,說明要支持UCOSIII
#define delay_osrunning OSRunning //OS是否運行標記,0,不運行;1,在運行
#define delay_ostickspersec OSCfg_TickRate_Hz //OS時鐘節(jié)拍,即每秒調(diào)度次數(shù)
#define delay_osintnesting OSIntNestingCtr //中斷嵌套級別,即中斷嵌套次數(shù)
#endif//us級延時時,關(guān)閉任務(wù)調(diào)度(防止打斷us級延遲)
void delay_osschedlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIIIOS_ERR err; OSSchedLock(&err); //UCOSIII的方式,禁止調(diào)度,防止打斷us延時
#else //否則UCOSIIOSSchedLock(); //UCOSII的方式,禁止調(diào)度,防止打斷us延時
#endif
}//us級延時時,恢復(fù)任務(wù)調(diào)度
void delay_osschedunlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIIIOS_ERR err; OSSchedUnlock(&err); //UCOSIII的方式,恢復(fù)調(diào)度
#else //否則UCOSIIOSSchedUnlock(); //UCOSII的方式,恢復(fù)調(diào)度
#endif
}//調(diào)用OS自帶的延時函數(shù)延時
//ticks:延時的節(jié)拍數(shù)
void delay_ostimedly(u32 ticks)
{
#ifdef CPU_CFG_CRITICAL_METHODOS_ERR err; OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err);//UCOSIII延時采用周期模式
#elseOSTimeDly(ticks); //UCOSII延時
#endif
}//systick中斷服務(wù)函數(shù),使用OS時用到
void SysTick_Handler(void)
{ if(delay_osrunning==1) //OS開始跑了,才執(zhí)行正常的調(diào)度處理{OSIntEnter(); //進入中斷OSTimeTick(); //調(diào)用ucos的時鐘服務(wù)程序 OSIntExit(); //觸發(fā)任務(wù)切換軟中斷}
}
#endif//初始化延遲函數(shù)
//當使用OS的時候,此函數(shù)會初始化OS的時鐘節(jié)拍
//SYSTICK的時鐘固定為AHB時鐘的1/8
//SYSCLK:系統(tǒng)時鐘頻率
void delay_init(u8 SYSCLK)
{
#if SYSTEM_SUPPORT_OS //如果需要支持OS.u32 reload;
#endifSysTick->CTRL&=~(1<<2); //SYSTICK使用外部時鐘源 fac_us=SYSCLK/8; //不論是否使用OS,fac_us都需要使用
#if SYSTEM_SUPPORT_OS //如果需要支持OS.reload=SYSCLK/8; //每秒鐘的計數(shù)次數(shù) 單位為M reload*=1000000/delay_ostickspersec; //根據(jù)delay_ostickspersec設(shè)定溢出時間//reload為24位寄存器,最大值:16777216,在168M下,約合0.7989s左右 fac_ms=1000/delay_ostickspersec; //代表OS可以延時的最少單位 SysTick->CTRL|=1<<1; //開啟SYSTICK中斷SysTick->LOAD=reload; //每1/delay_ostickspersec秒中斷一次 SysTick->CTRL|=1<<0; //開啟SYSTICK
#elsefac_ms=(u16)fac_us*1000; //非OS下,代表每個ms需要的systick時鐘數(shù)
#endif
} #if SYSTEM_SUPPORT_OS //如果需要支持OS.
//延時nus
//nus:要延時的us數(shù).
//nus:0~204522252(最大值即2^32/fac_us@fac_us=21)
void delay_us(u32 nus)
{ u32 ticks;u32 told,tnow,tcnt=0;u32 reload=SysTick->LOAD; //LOAD的值 ticks=nus*fac_us; //需要的節(jié)拍數(shù) delay_osschedlock(); //阻止OS調(diào)度,防止打斷us延時told=SysTick->VAL; //剛進入時的計數(shù)器值while(1){tnow=SysTick->VAL; if(tnow!=told){ if(tnow<told)tcnt+=told-tnow; //這里注意一下SYSTICK是一個遞減的計數(shù)器就可以了.else tcnt+=reload-tnow+told; told=tnow;if(tcnt>=ticks)break; //時間超過/等于要延遲的時間,則退出.} };delay_osschedunlock(); //恢復(fù)OS調(diào)度
}
//延時nms
//nms:要延時的ms數(shù)
//nms:0~65535
void delay_ms(u16 nms)
{ if(delay_osrunning&&delay_osintnesting==0)//如果OS已經(jīng)在跑了,并且不是在中斷里面(中斷里面不能任務(wù)調(diào)度) { if(nms>=fac_ms) //延時的時間大于OS的最少時間周期 { delay_ostimedly(nms/fac_ms); //OS延時}nms%=fac_ms; //OS已經(jīng)無法提供這么小的延時了,采用普通方式延時 }delay_us((u32)(nms*1000)); //普通方式延時
}
#else //不用ucos時
//延時nus
//nus為要延時的us數(shù).
//注意:nus的值,不要大于798915us(最大值即2^24/fac_us@fac_us=21)
void delay_us(u32 nus)
{ u32 temp; SysTick->LOAD=nus*fac_us; //時間加載 SysTick->VAL=0x00; //清空計數(shù)器SysTick->CTRL=0x01 ; //開始倒數(shù) do{temp=SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16))); //等待時間到達 SysTick->CTRL=0x00; //關(guān)閉計數(shù)器SysTick->VAL =0X00; //清空計數(shù)器
}
//延時nms
//注意nms的范圍
//SysTick->LOAD為24位寄存器,所以,最大延時為:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK單位為Hz,nms單位為ms
//對168M條件下,nms<=798ms
void delay_xms(u16 nms)
{ u32 temp; SysTick->LOAD=(u32)nms*fac_ms; //時間加載(SysTick->LOAD為24bit)SysTick->VAL =0x00; //清空計數(shù)器SysTick->CTRL=0x01 ; //開始倒數(shù) do{temp=SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16))); //等待時間到達 SysTick->CTRL=0x00; //關(guān)閉計數(shù)器SysTick->VAL =0X00; //清空計數(shù)器
}
//延時nms
//nms:0~65535
void delay_ms(u16 nms)
{ u8 repeat=nms/540; //這里用540,是考慮到某些客戶可能超頻使用,//比如超頻到248M的時候,delay_xms最大只能延時541ms左右了u16 remain=nms%540;while(repeat){delay_xms(540);repeat--;}if(remain)delay_xms(remain);
}
#endif
硬件設(shè)計
使用元器件:
單片機:STM32;
添加圖片注釋,不超過 140 字(可選)
設(shè)計資料
01程序
本設(shè)計使用軟件Keil5 MDK版本編程設(shè)計!具體如圖!
添加圖片注釋,不超過 140 字(可選)
02設(shè)計報告
一萬兩千字設(shè)計報告,具體如圖!
添加圖片注釋,不超過 140 字(可選)
03設(shè)計資料
全部資料包括程序(含注釋)、設(shè)計報告等。具體內(nèi)容如下,全網(wǎng)最全! !
添加圖片注釋,不超過 140 字(可選)
點贊分享一起學習成長。