版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
第1章嵌入式基礎知識1.1思政作業(yè):閱讀嵌入式系統(tǒng)發(fā)展歷史文獻,了解嵌入式系統(tǒng)的發(fā)展歷程及其對社會進步和科技發(fā)展的貢獻,撰寫一篇閱讀報告,其中報告格式不限,字數(shù)不少于800字。答:回答合理即可1.2簡述嵌入式系統(tǒng)國內(nèi)定義及國際定義。答:國際定義:用于控制、監(jiān)視或者輔助操作機器和設備的裝置。該定義是從應用上考慮的,嵌入式系統(tǒng)是軟件和硬件的綜合體,還可以涵蓋機電等附屬裝置,只要是一個專用的工控系統(tǒng)都可以認為是嵌入式系統(tǒng)。國內(nèi)定義:在國內(nèi),將嵌入式系統(tǒng)的一般定義是:是以應用為中心,通過軟硬件裁減,適應對功能、可靠性、成本、體積、功耗等要求的專用計算機系統(tǒng)。1.3簡述ARM公司與芯片廠家的關(guān)系。答:ARM公司本身不進行具體芯片生產(chǎn),它只負責設計處理器的構(gòu)架,即處理器最核心的部件,然后把這個核心部件技術(shù)授權(quán)給全球各大半導體廠家,芯片廠家在這個核心部件基礎上增加上外圍設備設計成具有特定功能的處理器,再賣給設備廠家。1.4簡述STM32F40x最小系統(tǒng)包括哪幾部分電路。答:在結(jié)構(gòu)上由片內(nèi)/片上外設、板上外設構(gòu)成,在電路上由芯片、電源電路、復位電路、振蕩電路、啟動電路組成。1.5舉例描述嵌入式系統(tǒng)的應用領域。答:嵌入式系統(tǒng)幾乎包括了生活中的所有電器設備,如掌上PDA、移動工控設備、電視機頂盒、手機、數(shù)字電視、多媒體、汽車導航儀、微波爐、數(shù)字相機、電梯控制器、空調(diào)控制器、安全控制系統(tǒng)、自動售貨機、消費電子設備、工業(yè)儀表與醫(yī)療儀器等。1.6總結(jié)馮·諾依曼體系結(jié)構(gòu)和哈佛結(jié)構(gòu)的特點。答:馮·諾依曼結(jié)構(gòu):把程序本身當作數(shù)據(jù)來對待,程序和該程序處理的數(shù)據(jù)用同樣的方式存儲,該結(jié)構(gòu)的主要特點:單一存儲、統(tǒng)一編址、分時復用。哈佛結(jié)構(gòu):使用兩個獨立的存儲器模塊,分別存儲指令和數(shù)據(jù),每個存儲模塊都不允許指令和數(shù)據(jù)并存;使用獨立的兩條總線,分別作為CPU與每個存儲器之間的專用通信路徑,而這兩條總線之間毫無關(guān)聯(lián),也就是該結(jié)構(gòu)分開存儲、獨立編址、兩倍帶寬、效率更高。第2章Keil開發(fā)環(huán)境及調(diào)試方法2.1完成STM32F4的KEILARMMDK5開發(fā)集成開發(fā)環(huán)境的安裝。答:自選根據(jù)書本介紹,動手實際安裝操作。2.2使用MDK5創(chuàng)建一個基本STM32F407工程,并且編寫一個基本的main函數(shù)。答:請根據(jù)STM32F407軟件開發(fā)環(huán)境搭建.pdf步驟完成。2.3擴展:請自選查閱資料,理解CMSIS的含義及常用的規(guī)范說明。答:CMSIS(CortexMicrocontrollerSoftwareInterfaceStandard),翻譯過來是ARMCortex?微控制器軟件接口標準。這個標準是ARM跟芯片廠商共同提出的,是為了不同芯片廠商生產(chǎn)的Cortex-M0/M3/M4芯片能在軟件上基本兼容,各芯片廠商只需要按照該標準實現(xiàn)自家芯片外設驅(qū)動程序,就是兼容CMSIS標準的。CMSIS在規(guī)范內(nèi)容很多,比如系統(tǒng)函數(shù)的命名、芯片初始化啟動流程等,如STM32的標準庫、HAL庫、LL庫驅(qū)動程序就是根據(jù)該標準寫的。關(guān)于CMSIS官方設備的框架結(jié)構(gòu)如下圖所示:
STM32F40x外設原理及控制方法3.1使用寄存器配置方式,如何使能端口F的硬件?答:查詢芯片手冊的外設時鐘寄存器可以知道F口在AHB1ENR寄存器的第5位,因此,只需要把RCC_AHB1ENR寄存器第5位設置為1即可:RCC->AHB1ENR|=1<<5;3.2使用寄存器配置方式,如何配置PF10為輸出模式、PE13為輸入模式?答: //開GGPF口時鐘 RCC->AHB1ENR|=1<<5; //配置GPF10:01通用輸出模式 GPIOF->MODER&=~(3<<10*2);//對應的兩位分別清0 GPIOF->MODER|=(1<<10*2);//對應的兩位分別設置為01 //配置默認輸出高電平 GPIOF->ODR|=1<<10; //開GPE,口時鐘 RCC->AHB1ENR|=1<<4; //配置GPF10:00輸入模式 GPIOE->MODER&=~(3<<13*2);//對應的兩位分別清0 //配置為:01:上拉--可選 GPIOE->PUPDR&=~(3<<13*2);//對應的兩位分別清0 GPIOE->PUPDR|=(1<<13*2);//對應的兩位分別設置為013.3使用寄存器配置方式,編寫引腳電平輸出控制函數(shù)。答:/**********************************************************************函數(shù)名:gpio_x_output_ctrl*功能描述:控制指定引腳輸出電平*作者:ZhifaChen*參數(shù)說明:gpio_obj:GPIO地址,如GPIOA,GPIOA,;*pin_num:本組引腳號;value:1或0*返回值:無*修改記錄:無*其他:**********************************************************************/voidgpio_x_output_ctrl(GPIO_TypeDef*gpio_obj,intpin_num,intvalue){if(value){gpio_obj->ODR|=(1<<pin_num);//輸出高電平}else{gpio_obj->ODR&=~(1<<pin_num);//輸出低電平}}3.4使用寄存器配置方式,編寫讀取輸入引腳電平的函數(shù)。答:/**********************************************************************函數(shù)名:gpio_x_read_pin*功能描述:讀取指定GPIO引腳電平*作者:ZhifaChen*參數(shù)說明:gpio_obj:GPIO地址,如GPIOA,GPIOA,;*pin_num:本組引腳號;*返回值:1:高電平,0低電平*修改記錄:無*其他:**********************************************************************/intgpio_x_read_pin(GPIO_TypeDef*gpio_obj,intpin_num){ //!!是把非1變成1,0還是0,因為一個引腳值一定是0或1 return!!(gpio_obj->IDR&(1<<pin_num));}3.5使用寄存器配置方式,根據(jù)圖3.80原理圖,實現(xiàn)跑馬燈功能。圖3.80LED電路圖答案見:homework-ch3-3.5l-leds工程3.6使用寄存器配置方式,根據(jù)圖3.81,實現(xiàn)按鍵控制燈的亮、滅,每個按鍵控制一個LED燈,實現(xiàn)按一下亮、再按一下滅,如此循環(huán)。圖3.81LED電路圖答案見:homework-ch3-3.6-button-leds工程3.7結(jié)合圖3.80和圖3.81,編程實現(xiàn)4個按鍵中斷,正確控制LED1~LED4的亮、滅。答案見:homework-ch3-3.7-button-leds-interrupt工程3.8編程實現(xiàn)三個按鍵中斷不同的搶占優(yōu)先級,且分別控制LED1~LED3,它們中斷搶占優(yōu)先級分別設置如下:按鍵1:搶占優(yōu)先級1按鍵2:搶占優(yōu)先級2按鍵3:搶占優(yōu)先級3①若輪流按下按鍵3>按鍵2>按鍵1,請說明LED1~LED3的亮、滅現(xiàn)象。②若輪流按下按鍵1>按鍵2>按鍵3,請說明LED1~LED3的亮、滅現(xiàn)象。答案見:homework-ch3-3.8-button-leds-interrupt-nest工程說明:1.代碼中在中斷服務程序是人為加入1.5S的延時,是為了方便模擬中斷執(zhí)行沒完時按鍵其他按鍵可以看到是否能嵌套中斷的效果。2.現(xiàn)象是按下KEY1,在1.5S內(nèi)按鍵KEY2或KEY3,都不會馬上響應,而是等待KEY1中斷程序執(zhí)行完成,會響應KEY2,KEY3,按下的中斷程序,也就是低優(yōu)先級不能嵌套高優(yōu)先級。反之,按下KEY3,在1.5S內(nèi)按鍵K2或K1,會馬上響應,而是不需要等待KEY3中斷程序執(zhí)行完成,就響應KEY2/KEY1的中斷程序,會馬上響應KEY1,KEY2,按下的中斷程序,也就是高優(yōu)先級可以嵌套高優(yōu)先級。其他順序分析方法如上面一樣,請自選寫。3.9描述串口數(shù)據(jù)幀中的起始位、數(shù)據(jù)位、停止位的作用。起始位:一幀數(shù)據(jù)中,用1個低電平位來表示通信的開始;數(shù)據(jù)位:長度是5~8位,通常是一個字節(jié)有效數(shù)據(jù),用來存放一幀要傳輸?shù)挠行?shù)據(jù)。停止位:傳輸一幀數(shù)據(jù)后停止1位或1.5位傳輸?shù)臅r間長度,用于消除異步通信會產(chǎn)生的時間積累誤差,或者說重新同步新的一幀數(shù)據(jù)傳輸,這樣才可以確保長時間通信數(shù)據(jù)傳輸?shù)恼_性。3.10編程實現(xiàn)串口中斷,正確控制LED1~LED4的亮、滅,要求如下:①接收到數(shù)據(jù)0x00,則LED1點亮;接收到數(shù)據(jù)0xF0,則LED1熄滅?、诮邮盏綌?shù)據(jù)0x01,則LED2點亮;接收到數(shù)據(jù)0xF1,則LED2熄滅?、劢邮盏綌?shù)據(jù)0x02,則LED3點亮;接收到數(shù)據(jù)0xF2,則LED3熄滅?、芙邮盏綌?shù)據(jù)0x03,則LED4點亮;接收到數(shù)據(jù)0xF3,則LED4熄滅!答案見:homework-ch3-3.9-leds-uart工程3.11描述I2C的起始信號、應答信號、停止信號的細節(jié)。答:起始信號:SCL和SDA初始化為高電平,開始通信時SCL高電平期間SDA由高變成低,其作用相當于總線復位,通知所有I2C從機準備開始通信了。應答信號:在每個字節(jié)傳輸后緊跟著一個應答位,即第9個時鐘SCL高電平期間,SDA是低電平表示應答信號,即告訴發(fā)送方數(shù)據(jù)已經(jīng)成功接收。停止信號:當主機不想通信了,停止通信的條件是SCL高電平期間SDA由低電平變成高電平,其作用是終止通信。3.12根據(jù)課本I2C時序圖,編寫代碼,實現(xiàn)向AT24C02的連續(xù)寫入與連續(xù)讀取。答案見:homework-ch3-3.12-at24c02工程3.13結(jié)合DMA和UART章節(jié)內(nèi)容,編寫代碼,實現(xiàn)串口1通過DMA方式發(fā)送數(shù)據(jù)。答案見:homework-ch3-3.13-uart-dma-send工程3.14綜合應用:結(jié)合定時器、UART實現(xiàn)程序運行時間統(tǒng)計并且存儲,以及通過UART與上位機通信修改存儲EEPROM中運行時間。答案見:homework-ch3-3.14-runtime-save-eeprom工程分析:在EEPROM讀寫工程基本上增加上定時器示例代碼記錄機器運行時間,需要考慮新機器第一次運行時是沒有正確的時間記錄的,而EEPROM中的數(shù)值是無法確定的,因此程序設計需要能識別當前是否是已經(jīng)設置過正確的運行時間,如果沒有設置過運行時間,則表示是新機器,此時設置運行時間為0,更新到EEPROM中。解決方法是在EERPOM中增加一個初始化的標志值,開機先讀取標志位置,判斷是否是正確的初始化標志值,如果是,則表示不是新機器,讀取此時的運行時間做當前起始時間,否則運行時間設置為0。為方便管理運行時間和已初始化標志,我們把他們設定為一個結(jié)構(gòu)體,并且規(guī)定初始化標志值,代碼片段如下所示:#defineRUNTIME_HAVE_INIT_VALUE0x12345678//已經(jīng)初始化過的標志值typedefstructruntime_data{u32second;//運行運行時間u32have_init;//是否是初始化了}runtime_data_t;定義時間存放變量和存儲地址,代碼片段如下所示#defineRUN_TIME_POS0x10//存放運行參數(shù)位置runtime_data_tg_runtime;//運行運行時間編寫更新運行時間和讀取時間函數(shù),調(diào)用AT24C02實現(xiàn)的讀寫函數(shù)即可/**********************************************************************函數(shù)名:update_runtime*功能描述:更新運行時間到EEPROM*作者:ZhifaChen*參數(shù)說明:無*返回值:無*修改記錄:無*其他:;**********************************************************************/voidupdate_runtime(runtime_data_trtime){AT24C02_PageWrite(0xa0,RUN_TIME_POS,(u8*)&rtime,sizeof(runtime_data_t));}/**********************************************************************函數(shù)名:read_runtime*功能描述:從EEPROM讀取運行時間*作者:ZhifaChen*參數(shù)說明:無*返回值:無*修改記錄:無*其他:;**********************************************************************/intread_runtime(runtime_data_t*rtime){intret;ret=AT24C02_ReadBytes(0xa0,RUN_TIME_POS,(u8*)rtime,sizeof(runtime_data_t));returnret;}在定時器中斷程序中1秒中增加1,用來做運行時間統(tǒng)計//定時器6中斷服務程序voidTIM6_DAC_IRQHandler(void){//由于定時器6和DAC模塊共用一個中斷入口地址,因此也共用一個中斷服務程序//這里先判斷是否是屬于定時器6產(chǎn)生的中斷,如果是再反轉(zhuǎn)LED燈if(TIM6->SR&(1<<0)){TIM6->SR&=~(1<<0);//清標志g_second++;}}在主程序中每5秒保存一次運行時間到EEPROM//每10秒保存一次運行時間,每秒保存頻率太高,容易損壞EEPROMif(g_second-g_second_pre>=5){g_second_pre=g_second;g_runtime.second+=5;//當前時間加5秒update_runtime(g_runtime);//寫入EEPROM,更新時間}再根據(jù)UART控制LED燈亮滅的示例增加串口命令來修改EEPROM中的運行時間,本示例有兩個清0運行時間和設置運行時間兩條指令:#defineCMD_RUN_TIME_CLR"RTM_CLR"http://清除運行時間//設置運行時間命令后面跟時間,單位秒,如RTM_SET123表示設置運行時間是123秒#defineCMD_RUN_TIME_SET"RTM_SET"解析代碼片段://判斷命令是否合法,合法,則執(zhí)行命令if(!strncmp((char*)uart_recv_buf,CMD_RUN_TIME_CLR,strlen(CMD_RUN_TIME_CLR))){g_runtime.second=0;//清除運行時間update_runtime(g_runtime);//寫入EEPROM,更新時間}elseif(!strncmp((char*)uart_recv_buf,CMD_RUN_TIME_SET,strlen(CMD_RUN_TIME_SET))){//命令示例:RTM_SET123g_runtime.second=atoi((char*)&uart_recv_buf[7]);//提示時間值數(shù)據(jù)update_runtime(g_runtime);//寫入EEPROM,更新時間}μC/OS-III實時操作系統(tǒng)原理及實踐4.1基于μC/OS-III,編寫一個任務,實現(xiàn)跑馬燈。答:分析說明:在本節(jié)基礎ucOS示例代碼基礎上進行修改,增加LED任務代碼即可。把裸機編寫的LED代碼添加到工作當中在main.c定義新增加的LED任務的相關(guān)變量,函數(shù)聲明,優(yōu)先級定義#defineTASK_LED_PRIO6//任務優(yōu)先級#defineTASK_LED_STK_SIZE128//任務堆棧大小OS_TCBtask_led_tcb;//任務控制塊CPU_STKtask_led_stk[TASK_LED_STK_SIZE];//任務堆棧voidtask_led_task(void*p_arg);//任務函數(shù)在start_task函數(shù)中增加一個任務創(chuàng)建,創(chuàng)建led任務//創(chuàng)建TaskLed任務OSTaskCreate((OS_TCB*)&task_led_tcb,//任務控制塊(CPU_CHAR*)"Taskled",//任務名字(OS_TASK_PTR)task_led_task,//任務函數(shù)(void*)0,//傳遞給任務函數(shù)的參數(shù)(OS_PRIO)TASK_LED_PRIO,//任務優(yōu)先級(CPU_STK*)&task_led_stk[0],//任務堆?;刂?CPU_STK_SIZE)TASK_LED_STK_SIZE/10,//任務堆棧深度限位(CPU_STK_SIZE)TASK_LED_STK_SIZE,//任務堆棧大小(OS_MSG_QTY)0,//任務內(nèi)部消息隊列能夠接收的最大消息數(shù)目,為0時禁止接收消息(OS_TICK)0,//當使能時間片輪轉(zhuǎn)時的時間片長度,為0時為默認長度,(void*)0,//用戶補充的存儲區(qū)(OS_OPT)OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,//任務選項(OS_ERR*)&err);//存放該函數(shù)錯誤時的返回值編寫led任務代碼,在其中編寫流水燈程序//taskled任務函數(shù)voidtask_led_task(void*p_arg){u8task1_num=0;OS_ERRerr;CPU_SR_ALLOC();p_arg=p_arg;while(1){gpio_x_output_ctrl(LED1_GPIO,LED1_PIN,LED_ON);OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err);//延時0.5sgpio_x_output_ctrl(LED2_GPIO,LED2_PIN,LED_ON);OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err);//延時0.5sgpio_x_output_ctrl(LED3_GPIO,LED3_PIN,LED_ON);OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err);//延時0.5sgpio_x_output_ctrl(LED4_GPIO,LED4_PIN,LED_ON);OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err);//延時0.5sgpio_x_output_ctrl(LED1_GPIO,LED1_PIN,LED_OFF);OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err);//延時0.5sgpio_x_output_ctrl(LED2_GPIO,LED2_PIN,LED_OFF);OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err);//延時0.5sgpio_x_output_ctrl(LED3_GPIO,LED3_PIN,LED_OFF);OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err);//延時0.5sgpio_x_output_ctrl(LED4_GPIO,LED4_PIN,LED_OFF);OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err);//延時0.5s}}完整工程,見:homework-ch4-4.1-ucos-leds4.2基于μC/OS-III,編寫一個任務管理LED亮、滅,一個任務用于識別按鍵狀態(tài),這兩個任務配合實現(xiàn)按鍵控制LED的亮、滅。答:分析說明:上一個示例代碼基礎上進行修改:創(chuàng)建一個消息隊列,在按鍵任務中檢測到有按鍵按下是把按鍵值放入消息隊列中修改LED任務:從消息隊列中讀取消息,轉(zhuǎn)換成按鍵值,根據(jù)按鍵值控制不同的LED燈新增加KEY任務:每20ms掃描一次按鍵狀態(tài),如檢測到有按鍵按下發(fā)送到消息隊列完整工程,見:homework-ch4-4.2-ucos-button-led4.3基于μC/OS-III,多任務利用互斥鎖實現(xiàn)串口發(fā)送數(shù)據(jù)的函數(shù)。答:分析說明:裸機的串口多字節(jié)發(fā)送在任務中使用,有可能在發(fā)送數(shù)據(jù)過程中被高優(yōu)先級的任務搶占,而高優(yōu)先級任務里又調(diào)用了串口發(fā)送函數(shù),這樣就會存在沖突,導致低優(yōu)先級的數(shù)據(jù)沒有輸送完成就被高優(yōu)先級任務搶占。解決方法,只需要把串口函數(shù)使用互斥信號量進行封裝一層即可。定義互斥信號量OS_MUTEXuart_debug_mutex;//定義一個互斥信號量在start_task任務中創(chuàng)建互斥信號量//創(chuàng)建一個互斥信號量OSMutexCreate((OS_MUTEX*)&uart_debug_mutex,(CPU_CHAR*)"uart_debug_mutex",(OS_ERR*)&err); 封裝串口發(fā)送函數(shù)/**********************************************************************函數(shù)名:os_uart_send_data*功能描述:加了互斥信號量保保護的串口發(fā)送函數(shù),可以防止任務搶占導致的數(shù)據(jù)混亂*作者:*參數(shù)說明:無*返回值:無*修改記錄:無*其他:;**********************************************************************/intos_uart_send_data(u8*data,u16num){ OS_ERRerr; OSMutexPend(&uart_debug_mutex,0,OS_OPT_PEND_BLOCKING,0,&err);//請求互斥信號量 uart_send_bytes(data,num);//這里是你自己的多字節(jié)發(fā)送函數(shù),根據(jù)實際情況替換即可 OSMutexPost(&uart_debug_mutex,OS_OPT_POST_NONE,&err);//釋放互斥信號量}完整工程,見:homework-ch4-4.3-ucos-mutex-uart4.4基于μC/OS-III,串口接收到的數(shù)據(jù)包通過消息隊列發(fā)送給任務處理。數(shù)據(jù)包如下:點亮LED1:”led-1-1#”熄滅LED1:”led-1-0#”點亮LED2:”led-2-1#”熄滅LED2:”led-2-0#”點亮LED3:”led-3-1#”熄滅LED3:”led-3-0#”點亮LED4:”led-4-1#”熄滅LED4:”led-4-0#”答:分析說明:在main.c中定義一個消息隊列存放串口消息//消息隊列定義#defineUART_MSG_Q_NUM8//串口消息隊列的數(shù)量OS_Quart_data_msg;//定義一個消息隊列, 在start_task任務中創(chuàng)建消息隊列//創(chuàng)建消息隊列uart_data_msgOSQCreate((OS_Q*)&uart_data_msg,//消息隊列指針(CPU_CHAR*)"uart_data_msg",//消息隊列名稱,自定義(OS_MSG_QTY)UART_MSG_Q_NUM,//消息隊列長度,(OS_ERR*)&err);//存放錯誤碼由于串口收到的數(shù)據(jù)長度可能不相同,收到后是放到消息隊列中,延后處理的,因此需要記錄實際數(shù)據(jù),為方便處理,我們可以定義一個結(jié)構(gòu)體來存放收到數(shù)據(jù)長度,收到的數(shù)據(jù),然后把該結(jié)構(gòu)存數(shù)據(jù)包放入消息隊列中,延后處理就可以很方便取出數(shù)據(jù)長度。在usart.h中添加以下結(jié)構(gòu)定義://定義串口消息結(jié)構(gòu),用來往消息隊列中存放typedefstruct{ u8data_len;//有效數(shù)據(jù)長度 u8data[128];//存放數(shù)據(jù)緩沖區(qū)}uart_data_t;main.c中創(chuàng)建串口處理任務,負責讀取隊列上的數(shù)據(jù),并且進行解析,控制LED,任務函數(shù)如下://讀取UART隊列上的數(shù)據(jù)來處理,根據(jù)處理結(jié)果控制LEDvoidtask_uart(void*p_arg){u8task1_num=0;OS_ERRerr;uart_data_t*msg_data;OS_MSG_SIZEsize;p_arg=p_arg;while(1){ //讀取按鍵任務發(fā)來的消息 msg_data=OSQPend((OS_Q*)&uart_data_msg, (OS_TICK)0, (OS_OPT)OS_OPT_PEND_BLOCKING, (OS_MSG_SIZE*)&size, (CPU_TS*)0, (OS_ERR*)&err); if(!strncmp("led-1-1#",(char*)msg_data->data,msg_data->data_len)){ gpio_x_output_ctrl(LED1_GPIO,LED1_PIN,LED_ON); }elseif(!strncmp("led-1-0#",(char*)msg_data->data,msg_data->data_len)){ gpio_x_output_ctrl(LED1_GPIO,LED1_PIN,LED_OFF); }elseif(!strncmp("led-2-1#",(char*)msg_data->data,msg_data->data_len)){ gpio_x_output_ctrl(LED2_GPIO,LED2_PIN,LED_ON); }elseif(!strncmp("led-2-0#",(char*)msg_data->data,msg_data->data_len)){ gpio_x_output_ctrl(LED2_GPIO,LED2_PIN,LED_OFF); }elseif(!strncmp("led-3-1#",(char*)msg_data->data,msg_data->data_len)){ gpio_x_output_ctrl(LED3_GPIO,LED3_PIN,LED_ON); }elseif(!strncmp("led-3-0#",(char*)msg_data->data,msg_data->data_len)){ gpio_x_output_ctrl(LED3_GPIO,LED3_PIN,LED_OFF); }elseif(!strncmp("led-4-1#",(char*)msg_data->data,msg_data->data_len)){ gpio_x_output_ctrl(LED4_GPIO,LED4_PIN,LED_ON); }elseif(!strncmp("led-4-0#",(char*)msg_data->data,msg_data->data_len)){ gpio_x_output_ctrl(LED4_GPIO,LED4_PIN,LED_OFF); } //回發(fā)給電腦顯示收到的結(jié)果 os_uart_send_data(msg_data->data,msg_data->data_len); }}在串口中斷服務中,當接收到完整一幀數(shù)據(jù)后,封裝成數(shù)據(jù)包發(fā)送到消息隊列上即可,本示例是在串口的空閑中斷位置增加代碼,如下:#defineUART_DATA_ARR_SIZE8//定義8個元素uart_data_tuart_data_arr[UART_DATA_ARR_SIZE];//定義全局的消息隊列數(shù)據(jù)包存放空間,u8uapos_cur=0;//用來指示當前使用的空閑位置voidUSART2_IRQHandler(void)//如果你使用UART1就是USART1_IRQHandler{省略//位4IDLE:檢測到空閑線路(IDLElinedetected)if(s&1<<4){省略uart2_recv_buf[index++%UART2_BUF_LEN]='\0';//添加接收字符串的結(jié)束標志index=0;//清接收計數(shù)器 //復制數(shù)據(jù)到緩沖區(qū)中 memcpy(&uart_data_arr[uapos_cur].data,uart2_recv_buf,uart2_recv_cnt+1); uart_data_arr[uapos_cur].data_len= uart2_recv_cnt+1; //發(fā)送當前數(shù)據(jù)到隊列中 externOS_Quart_data_msg;//聲明外部消息隊列 u8err; OSQPost((OS_Q*)&uart_data_msg, (void*)&uart_data_arr[uapos_cur], (OS_MSG_SIZE)sizeof(uart_data_t), (OS_OPT)OS_OPT_POST_FIFO, (OS_ERR*)&err); uapos_cur++; uapos_cur%=UART_DATA_ARR_SIZE;//更新下一個存儲位置 }}完整工程,見:homework-ch4-4.4-ucos-uart-ledsFATFS文件系統(tǒng)移植FATFS到STM32F407ZGT6。答:省略說明:請根書本描述完成文件系統(tǒng)移植操作,此處省略。使用FATFS的文件操作API實現(xiàn)創(chuàng)建目錄、文件復制、刪除文件、修改文件內(nèi)容、重命名文件。答:創(chuàng)建目錄復制文件#defineREAD_BUF_SIZE1024*4//定義緩沖區(qū)大小u8cpbuf[READ_BUF_SIZE];//定義緩沖區(qū)u8mf_copy(u8*psrc,u8*pdst){u8retry=0,res;u16br=0,bw=0;u8*fbuf=0;FIL_fsrc,_fdst;FIL*fsrc=&_fsrc,*fdst=&_fdst;fbuf=cpbuf;//復制數(shù)據(jù)臨時緩沖區(qū)//打開源文件,如果文件不存在就出錯res=f_open(fsrc,(constTCHAR*)psrc,FA_READ|FA_OPEN_EXISTING);if(res!=FR_OK){gotoout;}//以創(chuàng)建新文件形式打開一個文件,即新文件res=f_open(fdst,(constTCHAR*)pdst,FA_WRITE|FA_CREATE_ALWAYS);if(res!=FR_OK){gotoout;}//循環(huán)從源文件中復制數(shù)據(jù)寫入到新文件中while(res==FR_OK)//開始復制{br=0;res=f_read(fsrc,fbuf,READ_BUF_SIZE,(UINT*)&br);//源頭讀出4096字節(jié)if(res!=FR_OK){gotoout;}//文件完成了退出循環(huán)if(!br){break;}res=f_write(fdst,fbuf,(UINT)br,(UINT*)&bw);//寫入目的文件if(res||bw<br){gotoout;}}out:f_close(fdst);//closefilefdstf_close(fsrc);//closefilefsrcreturnres;}刪除文件:調(diào)用f_unlink函數(shù)即可刪除文件u8res=f_unlink(file_name);//刪除文件修改文件:以讀寫方式打開文件,然后讀取內(nèi)容出來到內(nèi)存中,修改內(nèi)存中的數(shù)據(jù)再回寫即可,值得注意的是,回寫數(shù)據(jù)前應該先f_lseek把讀寫指令調(diào)整到文件開頭。#defineREAD_BUF_SIZE1024*4//定義緩沖區(qū)大小u8cpbuf[READ_BUF_SIZE];//定義緩沖區(qū)u8modify_file_test(void){u8retry=0,res;u16br=0,bw=0;u8*fbuf=0;FIL_fsrc,_fdst;FIL*fsrc=&_fsrc;fbuf=cpbuf;//復制數(shù)據(jù)臨時緩沖區(qū)#defineFILE_NAME"1.txt"http://要修改的文件 //打開源文件,如果文件不存在就出錯res=f_open(fsrc,(constTCHAR*)FILE_NAME,FA_READ|FA_WRITE|FA_OPEN_EXISTING);if(res!=FR_OK){gotoout;}//循環(huán)從源文件中復制數(shù)據(jù)寫入到新文件中if(res==FR_OK)//開始復制{br=0;res=f_read(fsrc,fbuf,READ_BUF_SIZE,(UINT*)&br);//源頭讀出4096字節(jié)if(res!=FR_OK){gotoout;} //把修改后的數(shù)據(jù)重新寫入文件 //這里可以修改已經(jīng)讀取到fbuf中的數(shù)據(jù)了,以下把源數(shù)據(jù)6開始數(shù)據(jù)進行修改 strcpy((char*)&fbuf[6],"ABCDEFGHIJKLMN\r\n"); res=f_lseek(fsrc,0);//把文件讀寫指針移動到文件開頭if(res){gotoout;} res=f_write(fsrc,fbuf,(UINT)br,(UINT*)&bw);//寫入目的文件if(res||bw<br){gotoout;}}out:f_close(fsrc);//closefilefsrcreturnres;}重新命名文件:調(diào)用f_rename函數(shù)即可修改文件名u8res=f_rename("oldname.txt","newname.txt");編寫程序?qū)崿F(xiàn)接收電腦串口助手發(fā)送來的文件,并且保存到SD卡中。答:分析:以本章移植好的文件系統(tǒng)工程{smt32f407-sdio-fatfs-demo2}為基本模板,修改UART接收代碼,以及main.c中增加中增加把UART收到的數(shù)據(jù)寫入到文件中的代碼設計思路:文件可能很大,所以UART接收代碼需要做一點變動,即收到不能一次性接收完成所有文件數(shù)據(jù)再一次性寫入,這樣對RAM要求很大,解決方法是UART使用兩個接收緩沖區(qū),一個用來接收實時UART字節(jié)數(shù)據(jù),一個是存放等待寫入文件的數(shù)據(jù)緩沖區(qū)。即接收到一定數(shù)量,如512字節(jié)后就把接收緩沖區(qū)1數(shù)據(jù)復制到接收緩沖2,并且記錄實際數(shù)據(jù)長度,主程序判斷數(shù)據(jù)長度大于0就把緩沖區(qū)2的數(shù)據(jù)寫入到文件中。那文件發(fā)送完成一定是會進入UART的空閑中斷里,因此,在空閑中斷中設置標志,標識這時候是文件的最后一筆數(shù)據(jù)即可。UART代碼關(guān)鍵部分://接收數(shù)據(jù)需要一個緩沖區(qū)存放u8uart1_recv_buf[UART1_BUF_LEN]={0};//定義接收緩沖區(qū)u8uart1_recv_buf2[UART1_BUF_LEN]={0};//定義接收緩沖區(qū)2uint32_tuart1_flag=0;//接收完成標志uint32_tuart1_recv_index=0;//接收下標計數(shù)器uint32_tuart1_recv_cnt=0;//本次要處理的數(shù)字字節(jié)數(shù)量//UART中斷服務程序voidUSART1_IRQHandler(void){uint32_ts;s=USART1->SR;//讀取狀態(tài)寄存器//位5RXNE:讀取數(shù)據(jù)寄存器不為空(Readdataregisternotempty)//收到一個數(shù)據(jù)產(chǎn)生一個中斷,讀取收到的數(shù)據(jù)存儲到接收緩沖區(qū)數(shù)組中if(s&1<<5){//清接收中斷標志,請DR時候就清中斷標志uart1_recv_buf[uart1_recv_index++]=USART1->DR;USART1->SR&=~(1<<5);//也可能手動寫0清0 //一次處理512字節(jié)數(shù)量 if(uart1_recv_index>=512){ uart1_recv_index-=512;//跳過已經(jīng)復制的數(shù)據(jù) uart1_recv_cnt=512;//本次復制512字節(jié)數(shù)據(jù) //復制到處理緩沖區(qū)等待寫入sd卡 memcpy(uart1_recv_buf2,uart1_recv_buf,uart1_recv_cnt); }}//位4IDLE:檢測到空閑線路(IDLElinedetected)if(s&1<<4){//清空閑中斷標志:該位由軟件序列清零(讀入USART_SR寄存器,然后讀入USART_DR寄存器)s=USART1->SR;//讀取狀態(tài)寄存器USART1->DR;//這樣就是讀,不接收結(jié)果uart1_recv_buf[uart1_recv_index]='\0';//添加接收字符串的結(jié)束標志,可選的 uart1_recv_cnt=uart1_recv_index;//保存實際字節(jié)數(shù)量 uart1_recv_index=0;//清接收計數(shù)器 uart1_flag=1; //設置中斷處理標志 //復制到處理緩沖區(qū)等待寫入sd卡 memcpy(uart1_recv_buf2,uart1_recv_buf,uart1_recv_cnt);}}保存數(shù)據(jù)到文件的函數(shù) /********************************************************************* *函數(shù)名:gpio_x_read_pin *功能描述:把數(shù)據(jù)寫入到文件中 *作者:ZhifaChen *參數(shù)說明:fsrc:已經(jīng)打開的文件結(jié)構(gòu)指針;data:要保存的數(shù)據(jù)指針; *num:本組引腳號; *is_finish:是否是最后一筆數(shù)據(jù),1表示最后一筆數(shù)據(jù) *返回值:當前寫入的累積字節(jié)數(shù)量; *修改記錄:無 *其他: **********************************************************************/ u32save_file_test(FIL*fsrc,u8*data,u16num,u8is_finish) { staticu32write_num=0; u8res=FR_OK; u16bw=0; u32size=write_num; write_num+=num; //累加原來寫入的字節(jié) res=f_write(fsrc,data,(UINT)num,(UINT*)&bw);//寫入目的文件 if(res||bw<num) { f_close(fsrc);//closefilefsrc } if(is_finish){ write_num=0;//最后一筆數(shù)字寫入時清累計值 f_close(fsrc);//closefilefsrc } returnsize; }Main函數(shù)中關(guān)鍵代碼#defineFILE_NAME_MOD"uart-data.txt"http://保存的文件名intmain(void){原來的代碼省略 //打開源文件,如果文件不存在就出錯 res=f_open(&fdst,(constTCHAR*)FILE_NAME_MOD,FA_READ|FA_WRITE|FA_CREATE_ALWAYS); if(res!=FR_OK) { printf("f_openerror\r\n"); Delay_ms(1000); } while(1) { //如果有數(shù)據(jù)來對執(zhí)行寫入文件操作 if(uart1_recv_cnt) { save_file_test(&fdst,uart1_recv_buf2,uart1_recv_cnt,uart1_flag); uart1_recv_cnt=0; if(uart1_flag) { uart1_flag=0;//清接收完成標志 f_close(&fdst);//關(guān)閉文件,這樣文件會全部寫入sd卡 } } }}完整項目工程見homework-ch5-5.3-save-uart-data-to-file第6章分時操作系統(tǒng)Linux開發(fā)環(huán)境6.1安裝虛擬機、Ubuntu。答:省略說明:請根據(jù)配套完成PPT操作,此處省略。6.2配置Windows系統(tǒng)共享目錄。答:省略說明:請根據(jù)配套完成PPT操作,此處省略。第7章Linux系統(tǒng)命令及Vim使用7.1在Ubuntu系統(tǒng)中使用命令創(chuàng)建用戶(用戶名為自己的姓名拼音)并附上詳細的創(chuàng)建過程與截圖。答:創(chuàng)建用戶完成后,就可以注銷,使用新用戶登陸了。說明:sudouseradd-mxiaoming:表示創(chuàng)建新用戶xiaoming,并且自動生成/home目錄下用戶家目錄sudopasswdxiaoming:表示修改新用戶密碼sudousermod-a-Gsudoxiaoming:表示把xiaoming用戶添加到sudo組中,后面該用戶才可以使用sudo提升權(quán)限。補充:在創(chuàng)建用戶時建議增加-s/bin/bash來指定用戶默認shell,否則默認shell可能不是bash,使用會不習慣,當然可以通過后面修改,或動態(tài)命令修改。7.2根據(jù)以下的步驟,使用命令補充對應的內(nèi)容并附加截圖。示例:進入根目錄 cd/①進入Home目錄(注意:Home目錄必須對應題1的用戶)②詳細顯示Home目錄下所有文件與文件夾③在當前目錄下創(chuàng)建1.txt④升級系統(tǒng)(當前系統(tǒng)必須正確聯(lián)網(wǎng),且源選用國內(nèi)阿里云,才能快速升級),顯示升級進度即可。答:重啟Ubuntu系統(tǒng),使用上一步創(chuàng)建的新用戶登陸打開命令終端,如果創(chuàng)建用戶時沒有指定默認bash,則在命令中先選擇bash回車切換bashshell。以下開始執(zhí)行題目要求:Linux系統(tǒng)應用程序開發(fā)基礎8.1C語言從源代碼到可執(zhí)行文件需要經(jīng)歷四個相互關(guān)聯(lián)的步驟。答:①預處理器將源文件中的宏進行展開還原;②編譯器gcc將c文件編譯成匯編文件;③匯編器as將匯編文件編譯成機器碼;④鏈接器將目標文件和符號進行鏈接,其中包括*.c生成的*.o、引導代碼、庫函數(shù)代碼,最終生成一個可執(zhí)行二進制文件。8.2請寫出Makefile文件格式。答:目標1:依賴文件列表A#目標名:依賴項,其中目標名自己定義TAB鍵命令#必須以tab鍵開頭,然后寫想要執(zhí)行的命令。目標2:依賴文件列表B#目標名:依賴項,其中目標名自己定義。TAB鍵命令#必須以tab鍵開頭,然后寫想要執(zhí)行的命令。目標3:依賴文件列表C#目標名:依賴項,其中目標名自己定義。TAB鍵命令#必須以tab鍵開頭,然后寫想要執(zhí)行的命令。8.3請總結(jié)出緩沖區(qū)I/O和非緩沖I/O的特點。答:(1)非緩沖I/O非緩存I/O是指對設備的讀寫操作時,數(shù)據(jù)在用戶空間中沒有緩沖區(qū),直接寫入內(nèi)核空間緩沖區(qū)中。這類函數(shù)是Linux系統(tǒng)特有的文件I/O系統(tǒng)調(diào)用函數(shù),如read、write等,主要是針對數(shù)據(jù)實時性要求高的硬件設會采用非緩沖方式。(2)緩沖I/O對于緩沖I/O,在標準C庫里有一套專門的讀寫函數(shù),如fread、fwrite等。應用程序向硬盤寫數(shù)據(jù),首先用戶將數(shù)據(jù)寫入用戶空間的緩沖區(qū),等到緩沖區(qū)寫滿或者調(diào)用fflush刷新緩沖才將數(shù)據(jù)寫入內(nèi)核緩沖區(qū),再等到緩沖區(qū)寫滿或者調(diào)用fsync函數(shù)強制刷新緩沖區(qū)才最后寫入磁盤設備中。這種機制可以提高硬盤寫入效率。8.4請寫入統(tǒng)計1級深度目錄的所有文件大小,目錄名通過運行程序時在命令行參數(shù)傳入。答:該題目實際就是考察目錄讀取函數(shù)readdir以及文件狀態(tài)函數(shù)stat的使用。代碼如下:#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<dirent.h>#include<sys/stat.h>intmain(intargc,char**argv){DIR*target_dir;structdirent*target_dir_info;if(argc<2){target_dir=opendir(".");//打開當前目錄}elseif(argc==2){target_dir=opendir(argv[1]);}else{printf("格式:%s目錄路徑\r\n",argv[0]);//打開自定義目錄return0;}if(target_dir==NULL){perror("opendirerror!");//打開目錄失敗return-1;}while((target_dir_info=readdir(target_dir))!=NULL){//只處理普通文件,不處理目錄if(target_dir_info->d_type==DT_REG){structstatsb;//讀取文件信息if(stat(target_dir_info->d_name,&sb)==-1){perror("staterror!!!");continue;} printf("%-40s%lldbytes\r\n",target_dir_info->d_name,(longlong)sb.st_size);}}return0;}完整工程,見:homework-ch08-8.4-linux-io嵌入式LinuxRK3399開發(fā)環(huán)境構(gòu)建9.1安裝GCC交叉編譯器、編譯U-Boot、編譯Linux內(nèi)核。答:省略說明:請根據(jù)PPT完成交叉編譯器,U-boot,Linux內(nèi)核編譯。9.2燒錄U-boot、linux內(nèi)核和根文件系統(tǒng)到目標板,并且使用串口終端登錄練習常用命令。答:省略說明:請根據(jù)《01-RK3399開發(fā)環(huán)境及系統(tǒng)燒寫-note》完成系統(tǒng)固件下載,并且使用串口終端登陸開發(fā)板上的Ubuntu系統(tǒng),按課本完成常用命令練習。嵌入式Linux系統(tǒng)驅(qū)動程序設計10.1詳細描述主設備號、次設備號的用途。答:Linux系統(tǒng)字符設備和塊設備都有設備號,設備號由主設備號和次設備號組成,主設備號:在驅(qū)動程序用來標識一類設備次設備號:在驅(qū)動程序用來表示一類設備中具體哪一個設備比如,開發(fā)板有5個串口設備,其設備文件的主設備號相同,而每個次設備號卻是不相同的,內(nèi)核就是通過主設備號和次設備號來找到驅(qū)動程序正確操作具體的硬件設備。10.2寫出初始化LED1、LED2、LED3、LED4對應I/O引腳的驅(qū)動代碼。答:分析說明:假設LED1~LED4分別在GPIO0_B5,6,7,GPIO0_C0引腳上,我們可以仿照LED驅(qū)動程序?qū)O口的使用方法寫出初始化代碼。使用gpio_request申請gpio使用使用gpio_direction_output配置引腳為輸出方向代碼片段如下://定義led數(shù)據(jù)結(jié)構(gòu)structled_info{intid;//id,可選char*name;//名字,可選unsignedintgpio;//gpio編號};//實例化LED1~4使用到的GPIO引腳staticstructled_infoleds_data[]={{0,"led-0",8+5}/*GPIO0_B5*/{0,"led-0",8+6}/*GPIO0_B6*/{0,"led-0",8+7}/*GPIO0_B7*/{0,"led-0",8*2+0}/*GPIO0_C0,組偏移16*/ };//模塊初始化函數(shù)staticint__initxyd_rk3399_led_init(void){intret=0,i;for(i=0;i<ARRAY_SIZE(leds_data);i++){ret=gpio_request(leds_data[i].gpio,leds_data[i].name);//申請GPIOif(ret<0){printk("gpio_requesterror\n");gotoerror_gpio_request;}gpio_direction_output(leds_data[i].gpio,0);//配置為輸出方向,輸出低電平}其他無關(guān)代碼省略error_gpio_request:while(--i>=0){gpio_free(leds_data[i].gpio);}returnret;}10.3編寫一個綜合應用程序分別調(diào)用LED驅(qū)動和按鍵驅(qū)動,實現(xiàn)按鍵控制LED燈亮滅。答:#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#include<sys/ioctl.h>#include<sys/types.h>#include<errno.h>#include<poll.h>#include<sys/select.h>#include<sys/time.h>#include<sys/types.h>#include<unistd.h>//由于一個按鍵控制一個LED,因此定義的數(shù)量相同,//注意不能超過真實硬件LED和按鍵數(shù)量,同時還受你實現(xiàn)的驅(qū)動程序限定的數(shù)量限制#defineBTN_SIZE1//按鍵數(shù)量#defineLED_NUMBTN_SIZE//LED燈數(shù)量//請根據(jù)自己編寫的驅(qū)動程序來修改#defineDEV_BTN"/dev/xyd-buttons"http://按鍵設備名#defineDEV_LED"/dev/xyd-leds"http://LED設備名intmain(intargc,char*argv[]){intfd_key,fd
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025工程大學項目采購購銷合同書
- 2025公司轉(zhuǎn)讓合同協(xié)議版
- 2025含競業(yè)禁止條款的勞動合同
- 老年人視角下的家庭醫(yī)療輔助設備評價
- 提升客戶體驗-實現(xiàn)銷售增長的秘密武器
- 2024年戶外機柜溫控節(jié)能項目投資申請報告代可行性研究報告
- 游戲化教學法在小學數(shù)學中的推廣與應用
- 教育領域中的小學數(shù)學思維訓練研究
- 小學數(shù)學與邏輯思維培養(yǎng)
- 2024-2025學年度第一學期期末考試八年級歷史試卷
- 2025-2030年中國草莓市場競爭格局及發(fā)展趨勢分析報告
- 第二章《有理數(shù)的運算》單元備課教學實錄2024-2025學年人教版數(shù)學七年級上冊
- 華為智慧園區(qū)解決方案介紹
- 奕成玻璃基板先進封裝中試線項目環(huán)評報告表
- 廣西壯族自治區(qū)房屋建筑和市政基礎設施全過程工程咨詢服務招標文件范本(2020年版)修訂版
- 人教版八年級英語上冊期末專項復習-完形填空和閱讀理解(含答案)
- 2024新版有限空間作業(yè)安全大培訓
- GB/T 44304-2024精細陶瓷室溫斷裂阻力試驗方法壓痕(IF)法
- 年度董事會工作計劃
- 《退休不褪色余熱亦生輝》學校退休教師歡送會
- 02R112拱頂油罐圖集
評論
0/150
提交評論