Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

[嵌入式系統] MCS-51 實驗 - 使用 IAR (3)

https://www.facebook.com/eeRhapsody
MCS-51 實驗 - 使用 IAR (3)

  • Login to see the comments

[嵌入式系統] MCS-51 實驗 - 使用 IAR (3)

  1. 1. Chien-Jung Li Nov. 2013 MCS-51 基礎實習 使用IAR Embedded Workbench (III)
  2. 2. Lab11: Real-Time Clock晶片 2
  3. 3. DS1302 RTC介紹 3  DS1302是美國DALLAS公司生產的即時時鐘電路(Real- time clock, RTC),它可對年、月、日、周日、時、分、 秒進行計時並具有閏年補償功能,而且也有24小時制 與12小時制(AM/PM)的選擇。  工作電壓為 2.0V~5.5V,採用三線通訊介面(3-wire interface)。內部具有31 Bytes的SRAM。  DS1302具有主電源/備用電源的雙電源引腳(VCC1為後備 電源,VCC2為主電源,由VCC1 或VCC2 兩者中的較大者 供電),同時提供對備用電源進行涓流充電的能力。  X1和X2外接32.768 kHz的石英振盪器。RST是重置/晶片 選擇腳,對RST輸入Low重置晶片而將RST設為High可啟 動所有資料傳送。
  4. 4. DS1302 RTC的RST/CE接腳功能 4  RST/CE輸入有兩種功能:  RST接至控制邏輯,允許位址/命令序列送入移位暫存器  RST提供終止資料傳送。當RST為高電壓時,所有的數據傳送被初始化, 允許對DS1302進行操作。如果在傳送過程中RST置為低電壓,則會終止 此次資料傳送,I/O引腳變為高阻態。  啟動運行時,在VCC>2.0V之前,RST必須保持低電位。只有在SCLK為低 電位時,才能將RST置為高電位。I/O為串列資料輸出端(雙向)。SCLK為 時鐘輸入端。 40 kΩ pull-down
  5. 5. DS1302之指令 – Command Byte 5  Command Byte用於初始化每次的資料傳輸,bit-0必 定為input staring。
  6. 6. 3-Wire通訊介面的讀寫 6 Burst mode: command byte bit1~5 = 11111’b = 31(decimal) Reads or writes in burst mode start with bit 0 of address 0.
  7. 7. RTC內部暫存器(儲存時間資訊) 7
  8. 8. Trickle Charger (涓流充電) 8
  9. 9. Timing Diagram 9
  10. 10. 實習11 10  目標:製作一個電子時鐘,將日期與時間顯示在LCD上。 這是我們第一次要同時控制兩個較複雜的裝置,它們 的驅動程式如果寫在一個.c檔,程式檔會變很龐大。現 在我們要開始學習如何管理程式碼,這是進入商用產 品開發的第一站。  DS1302 RTC使用3-wire介面與MCU通訊  LCD使用LCD1602A的訊號介面與MCU通訊  練習1: 結構化你的程式碼  練習2: 加入LCD的驅動程式  練習3: 練習撰寫API手冊(以LCD驅動程式為例)  練習4: 加入3-wire通訊介面與DS1302的驅動程式  練習5: 完成電子時鐘
  11. 11. 設計模式與驅動程式 11  在開始談論如何結構化程式碼之前,我們先來討論 幾種跟硬體相關的嵌入式程式設計模式。  所講到的觀念,以後會慢慢應用在我們的設計專案 當中(有些觀念其實你已經不知不覺接觸很久了)。
  12. 12. Adapter(或Wrapper)模式 12  Adapter是十分傳統的設計模式,它將一個物件的介面 轉換成另一個用戶(高階模組)較易使用的介面。  通常,adapter覆蓋在軟體API之上以蓋掉醜陋的介面。
  13. 13. 閃爍LED燈 – 最簡單的寫法 13 #include<ioAT89C52.h> typedef unsigned char uint8; void delayms(uint8); void main(void) { P1_bit.P1_0 = 1; while(1) { P1_bit.P1_0 = 0; delayms(250); P1_bit.P1_0 = 1; delayms(250); } } #include<ioAT89C52.h> #define LED0 P1_bit.P1_0 typedef unsigned char uint8; void delayms(uint8); void main(void) { LED0 = 1; while(1) { LED0 = 0; delayms(250); LED0 = 1; delayms(250); } }
  14. 14. 閃爍LED燈 – 使用機板標頭檔 14 // ioMapping.h #define LED_REGISTER P0 #define LED_BIT (1 << 0) #include<ioAT89C52.h> #include "ioMapping.h" typedef unsigned char uint8; void delayms(uint8); void main(void) { LED_REGISTER |= LED_BIT; while(1) { LED_REGISTER &= ~LED_BIT; delayms(250); LED_REGISTER |= LED_BIT; delayms(250); } }
  15. 15. 閃爍LED燈 – 通用機板標頭檔 15 #include<ioAT89C52.h> #include "ioMapping.h" typedef unsigned char uint8; void delayms(uint8); void main(void) { LED_REGISTER |= LED_BIT; while(1) { LED_REGISTER &= ~LED_BIT; delayms(250); LED_REGISTER |= LED_BIT; delayms(250); } } // ioMapping.h #if COMPILING_BOARD_V1 #include "ioMapping_v1.h" #elif COMPILING_BOARD_V2 #include "ioMapping_v2.h" #else #error "No I/O map selected for the board" #endif // ioMapping_v1.h #define LED_REGISTER P0 #define LED_BIT (1 << 0) // ioMapping_v2.h #define LED_REGISTER P3 #define LED_BIT (1 << 4)
  16. 16. I/O處理程式碼 16
  17. 17. 閃爍LED燈 – Facade模式 17  LED的I/O子系統介面與內容,就是LED的驅動程式  隱藏子系統的細節是良好設計中十分重要的一環, 呼叫端的程式不會依賴子系統的細節 Main
  18. 18. 加上按鈕 18
  19. 19. 設定中斷 19  雖然為腳位設定中斷與設定輸入都是屬於初始化,但 這兩件事情通常會將實作分離,只需要在使用中斷的 程式碼中包含設定中斷的複雜度。  三個中斷處理函式(有時會用巨集來做)
  20. 20. 競賽情況(Race Condition)  在工作間共享記憶體十分危險,必須十分小心。 20
  21. 21. 避免競賽情況 – 使用mutex 21  任何工作間共享的記憶體不論是讀取或寫入,都要在 程式中建立臨界區域(critical section),表示正在存取共 享資源(記憶體或設備),必須保護共享資源,同一時間 只能讓一個工作修改,稱為互斥(mutual exclusion),簡 寫為mutex。  對於包含OS的系統,當兩個非中斷工作同時執行時, 能夠透過mutex表示兩個工作共享相同的資源,只需要 簡單地透過變數表示資源(或全域變數)可以供其他工作 使用就行了。  當其中之一是中斷時,資源所有權的改變必須是單元 動作(atomic),單元動作是指無法被系統其他部分中斷 的動作。
  22. 22. 結構化你的程式碼: Source Tree 22  Source Tree: 擺放原始碼檔案的目錄結構,基本原則是一個目錄可以對應到系 統架構中的一個方塊。  還記得我們在學C語言時,可以藉由撰寫Makefile來幫 助我們同時編譯多個原始碼嗎?  在開發系統時,你必須告訴寫Makefile的工程師那些要 編譯的檔案放在哪裡,source tree結構規範就是在告訴 工程師這件事。  寫Makefile這件事情有點麻煩,幸好我們有IDE開發環境 可以使用,我們只要將各種原始碼檔案分門別類放好, 再告訴IDE這些東西的Path在哪裡,剩下的就交給它吧!
  23. 23. 常見目錄名稱的意思 23 • /Driver: 驅動程式目錄 (有時也會用/hal) /Boot-Loader: 開機程式 /Hardware: 各種硬體裝置的驅動程式 /Include: 驅動程式的header files /API: 將所有驅動程式包裝成API /Boot: Boot程式 /LCD: LCD程式 /SDRAM: SDRAM驅動程式 • /System: 系統程式 /Include: 系統程式的header files /API: 將所有系統程式包裝成API /Common: 系統中的通用功能 /RTOS: 嵌入式OS的目錄 /Include: RTOS的header /Memory: 記憶體管理 /Sync: Task間同步機制 /IPC: Task間通訊機制 /Glib: 圖形函式庫 /Sub-System:各種子系統 /GUI: 圖形用戶介面 /TCPIP: TCPIP通訊堆疊 /FileSystem: 檔案系統 • /AP: 應用程式 (或/APP) /Include: 應用程式的header files /Source: 應用程式的原始碼 /Common: 應用程式的通用功能 /AP1: 應用程式1 /AP2: 應用程式2 /Resource: 應用程式的圖形、字串資源 • /Third_Party_Lib: 第三方函式庫 /HandWriting: 手寫辨識函式庫 /Fonts: 字型 /VoiceComp: 聲音壓縮函式庫 • /Include: header, sys_config.h(系統配置檔) • /Build: 製作映像檔(執行檔)的東西, 如makefile跟link script • /Tools: 開發中所需的程式,例如compiler • /Documents: 開發規範、datasheet、user guide、 Spec, API手冊等
  24. 24. 練習1: 結構化你的程式碼 24  在D槽新建一個目錄結構  D:MySimpSystem
  25. 25. 在IAR中New一個Worksapce 25
  26. 26. 環境設定 26
  27. 27. New一個應用程式File 27
  28. 28. 建立Groups 28
  29. 29. 完成以下的Groups 29
  30. 30. 先把幾個Header File歸入Group 30 D:MySimpSystemhaltargetJC51B D:MySimpSystemhalinclude
  31. 31. hal_types.h /***************************************************** Filename: hal_types.h Revised: $Date: 2013-10-18 15:20 $ Revision: $Revision: $ Description: Some useful typedef and definitions ******************************************************/ #ifndef _HAL_TYPES_H #define _HAL_TYPES_H /* Types */ typedef signed char int8; typedef unsigned char uint8; typedef signed short int16; typedef unsigned short uint16; typedef signed long int32; typedef unsigned long uint32; typedef unsigned char bool; /* Standard Defines */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef NULL #define NULL 0 #endif #ifndef HIGH #define HIGH 1 #endif #ifndef LOW #define LOW 0 #endif /* Memory Attributes */ /* ----------- IAR Compiler ----------- */ #ifdef __IAR_SYSTEMS_ICC__ #define CODE __code #define XDATA __xdata /* ----------- GNU Compiler ----------- */ #elif defined __KEIL__ #define CODE code #define XDATA xdata /* ------- Unrecognized Compiler ------ */ #else #error "ERROR: Unknown compiler." #endif /****************************************** */ #endif 31 D:MySimpSystemhaltargetJC51B
  32. 32. hal_mcu.h 32 /************************************************************** Filename: hal_mcu.h Revised: $Date: 2013-10-18 $ Revision: $Revision: $ Description: Describe the purpose and contents of the file. ****************************************************************/ #ifndef _HAL_MCU_H #define _HAL_MCU_H /* Target : AT89C52 (8051 core) */ /* Includes */ #include "hal_defs.h" #include "hal_types.h" /* Target Defines */ #define HAL_MCU_AT89C52 /* Compiler Abstraction */ /* ---------------------- IAR Compiler ---------------------- */ #ifdef __IAR_SYSTEMS_ICC__ #include <ioAT89C52.h> #define HAL_COMPILER_IAR #define HAL_MCU_LITTLE_ENDIAN() __LITTLE_ENDIAN__ #define _PRAGMA(x) _Pragma(#x) #define HAL_ISR_FUNC_DECLARATION(f,v) _PRAGMA(vector=v) __near_func __interrupt void f(void) #define HAL_ISR_FUNC_PROTOTYPE(f,v) _PRAGMA(vector=v) __near_func __interrupt void f(void) #define HAL_ISR_FUNCTION(f,v) HAL_ISR_FUNC_PROTOTYPE(f,v); HAL_ISR_FUNC_DECLARATION(f,v) /* ---------------------- Keil Compiler ---------------------- */ #elif defined __KEIL__ #include <reg51.h> D:MySimpSystemhaltargetJC51B #define HAL_COMPILER_KEIL #define HAL_MCU_LITTLE_ENDIAN() 0 #define HAL_ISR_FUNC_DECLARATION(f,v) void f(void) interrupt v #define HAL_ISR_FUNC_PROTOTYPE(f,v) void f(void) #define HAL_ISR_FUNCTION(f,v) HAL_ISR_FUNC_PROTOTYPE(f,v); HAL_ISR_FUNC_DECLARATION(f,v) /* ------------ Unrecognized Compiler ---------- */ #else #error "ERROR: Unknown compiler." #endif #pragma vector = extern0 __interrupt void Int_Extern0(void)
  33. 33. 33 /* Interrupt Macros */ #define HAL_ENABLE_INTERRUPTS() st( IE_bit.EA = 1; ) #define HAL_DISABLE_INTERRUPTS() st( IE_bit.EA = 0; ) #define HAL_INTERRUPTS_ARE_ENABLED() (IE_bit.EA) typedef unsigned char halIntState_t; #define HAL_ENTER_CRITICAL_SECTION(x) st( x = IE_bit.EA; HAL_DISABLE_INTERRUPTS(); ) #define HAL_EXIT_CRITICAL_SECTION(x) st( IE_bit.EA = x; ) #define HAL_CRITICAL_STATEMENT(x) st( halIntState_t _s; HAL_ENTER_CRITICAL_SECTION(_s); x; HAL_EXIT_CRITICAL_SECTION(_s); ) #ifdef __IAR_SYSTEMS_ICC__ /* This workaround should only be used with 8051 using IAR compiler. When IAR fixes the problem * of XCH instruction with EA, compile the following macros to null to disable them. */ #define HAL_ENTER_ISR() { halIntState_t _isrIntState = EA; HAL_ENABLE_INTERRUPTS(); #define HAL_EXIT_ISR() IE_bit.EA = _isrIntState; } #else #define HAL_ENTER_ISR() #define HAL_EXIT_ISR() #endif /* __IAR_SYSTEMS_ICC__ */ /************************************************************************************************** */ #endif
  34. 34. hal_board.h & hal_board_cfg.h 34 D:MySimpSystemhalinclude D:MySimpSystemhaltargetJC51B #include "hal_board_cfg.h" /********************************************* Filename: hal_board_cfg.h Revised: $Date: 2013-10-18 $ Revision: $Revision: $ Description: Declarations for the JC51B Development Board. **********************************************/ #ifndef HAL_BOARD_CFG_H #define HAL_BOARD_CFG_H /* ------------------------------------------ * Includes * ------------------------------------------ */ #include "hal_mcu.h" #include "hal_defs.h" #include "hal_types.h" #endif /********************************************* */
  35. 35. hal_defs.h 35 /***************************************************************** Filename: hal_defs.h Revised: $Date: 2013-10-18 14:48 $ Revision: $Revision: $ Description: This file contains useful macros and data types ******************************************************************/ #ifndef HAL_DEFS_H #define HAL_DEFS_H /* Macros */ #ifndef BV #define BV(n) (1 << (n)) #endif /* takes a byte out of a uint32 : var - uint32, ByteNum - byte to take out (0 - 3) */ #define BREAK_UINT32( var, ByteNum ) (uint8)((uint32)(((var) >>((ByteNum) * 8)) & 0x00FF)) #define BUILD_UINT32(Byte0, Byte1, Byte2, Byte3) ((uint32)((uint32)((Byte0) & 0x00FF) + ((uint32)((Byte1) & 0x00FF) << 8) + ((uint32)((Byte2) & 0x00FF) << 16) + ((uint32)((Byte3) & 0x00FF) << 24))) #define BUILD_UINT16(loByte, hiByte) ((uint16)(((loByte) & 0x00FF) + (((hiByte) & 0x00FF) << 8))) #define HI_UINT16(a) (((a) >> 8) & 0xFF) #define LO_UINT16(a) ((a) & 0xFF) /* This macro is for use by other macros to form a fully valid C statement. */ #define st(x) do { x } while (__LINE__ == -1) /********************************************************** */ #endif D:MySimpSystemhalinclude
  36. 36. hal_drivers.h 36 /**************************************************** Filename: hal_drivers.h Revised: $Date: 2013-10-18 14:52 $ Revision: $Revision: $ Description: This file contains the interface to the Drivers service. *****************************************************/ #ifndef HAL_DRIVER_H #define HAL_DRIVER_H /* Initialize HW */ extern void HalDriverInit (void); /**************************************** ****************************************/ #endif D:MySimpSystemhalinclude
  37. 37. 練習2: 加入LCD的驅動程式 #include<ioAT89C52.h> #define BTN1 P3_bit.P3_2 #define BTN2 P3_bit.P3_3 #define LCD_RW P1_bit.P1_1 #define LCD_EN P3_bit.P3_4 #define LCD_RS P3_bit.P3_5 #define LCD_BF P0_bit.P0_7 #define LCD_DATA_PORT P0 #define LCD_SEL_CMD 0 #define LCD_SEL_DATA 1 #define LCD_IO_WRITE 0 #define LCD_IO_READ 1 typedef unsigned char uint8; D:MySimpSystemhalinclude /* HD44780 Commands */ #define LCD_CMD_CLS 0x01 // Clear display (also DDRAM) #define LCD_CMD_FNCT_1 0x30 // 8-bits, 1 line #define LCD_CMD_FNCT_2 0x38 // 8-bits, 2 line #define LCD_CMD_FNCT_3 0x20 // 4-bits, 1 line #define LCD_CMD_FNCT_4 0x28 // 4-bits, 2 line #define LCD_CMD_ENTRY_MODE 0x06 // Entry mode #define LCD_CMD_DON_COFF 0x0C // LCD ON, Cursor OFF, Blink OFF #define LCD_CMD_DON_CON 0x0E // LCD ON, Cursor ON, Blink OFF #define LCD_CMD_DON_CON_BLN 0x0F // LCD ON, Cursor ON, Blink ON #define LCD_CMD_SHIFT_LEFT 0x18 // Shift entire display left #define LCD_CMD_SHIFT_RIGHT 0x1C // Shift entire display right #define LCD_CMD_CMOVE_LEFT 0x10 // Cursor move left by one char #define LCD_CMD_CMOVE_RIGHT 0x14 // Cursor move right by one char /* DDRAM and CGRAM Initial Address */ #define LCD_DDRAM_ADDR0 0x80 #define LCD_DDRAM_ADDR1 0xC0 #define LCD_CGRAM_ADDR0 0x40 37
  38. 38. 38 static void LCD_CursorSet(uint8 row, uint8 col); void LCD_DataWr(uint8 data); void LCD_CmdWr(uint8 cmd); extern void LCD_Init(uint8 maxrows, uint8 maxcols); extern void LCD_DispChar(uint8 row, uint8 col, char c); extern void LCD_DispStr(uint8 row, uint8 col, char *s); extern void LCD_ClrLine(uint8 line); extern void LCD_ClrScr(void); extern void LCD_DefChar(uint8 id, uint8 *pat); extern void LCD_DispHorBarInit(void); extern void LCD_DispHorBar(uint8 row, uint8 col, uint8 val); void delayms(uint8 time);
  39. 39. 39 D:MySimpSystemhaltargetJC51B /********************************************* Filename: hal_lcd.c Revised: $Date: 2013-10-19 16:21 $ Revision: $Revision: $ Description: *********************************************/ /******* INCLUDES *******/ #include "hal_board_cfg.h" #include "hal_defs.h" #include "hal_types.h" #include "hal_lcd.h" /******* CONSTANTS ******/ #define LCD_CMD_FNCT LCD_CMD_FNCT_2 // 8-bits, 2 line #if (HAL_LCD == TRUE) /******* LOCAL VARIABLES *********/ char StrL1[]="LCD 1602 Test"; char StrL2[]="Start LCD OK!"; static uint8 LCD_MaxCols; static uint8 LCD_MaxRows; // Patterns of horizontal bar static uint8 LCD_DispBar1[] = {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}; static uint8 LCD_DispBar2[] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}; static uint8 LCD_DispBar3[] = {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C}; static uint8 LCD_DispBar4[] = {0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E}; static uint8 LCD_DispBar5[] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F}; /******* FUNCTIONS – API ********/ /**** LOCAL FUNCTIONS *****/ static void LCD_BusyCheck(void); static void LCD_DataWr(uint8 data); static void LCD_CmdWr(uint8 cmd); static void LCD_CursorSet(uint8 row, uint8 col); #endif #if (HAL_LCD == TRUE) … #endif
  40. 40. 40 /***************************************************************** * @fn LCD_Init * @brief LCD initialization * @param maxrows: max line number, maxcols: max word numbers * @return None *****************************************************************/ void LCD_Init(uint8 maxrows, uint8 maxcols) { #if (HAL_LCD == TRUE) LCD_MaxCols = maxcols; LCD_MaxRows = maxrows; delayms(30); LCD_EN = LOW; LCD_RS = LOW; LCD_RW = LOW; LCD_CmdWr(LCD_CMD_FNCT); delayms(5); LCD_CmdWr(LCD_CMD_FNCT); delayms(5); LCD_CmdWr(LCD_CMD_FNCT); delayms(5); LCD_CmdWr(LCD_CMD_FNCT); LCD_CmdWr(LCD_CMD_DON_COFF); LCD_CmdWr(LCD_CMD_ENTRY_MODE); LCD_CmdWr(LCD_CMD_CLS); delayms(2); #endif }
  41. 41. 41 void LCD_DispChar(uint8 row, uint8 col, char c) { #if (HAL_LCD == TRUE) 略 #endif } void LCD_DispStr(uint8 row, uint8 col, char *s) { #if (HAL_LCD == TRUE) 略 #endif } void LCD_ClrLine(uint8 line) { #if (HAL_LCD == TRUE) 略 #endif } void LCD_ClrScr(void) { #if (HAL_LCD == TRUE) 略 #endif } void LCD_DefChar(uint8 id, uint8 *pat) { #if (HAL_LCD == TRUE) 略 #endif } void LCD_DispHorBarInit(void) { #if (HAL_LCD == TRUE) 略 #endif } void LCD_DispHorBar(uint8 row, uint8 col, uint8 val) { #if (HAL_LCD == TRUE) 略 #endif }
  42. 42. 42 /******** LOCAL FUNCTIONS *************/ #if (HAL_LCD == TRUE) /*********************************************** * @fn LCD_BusyCheck * @brief Check if LCD is busy by Busy Flag (BF) * @param data: the data to be written * @return None *************************************************/ void LCD_BusyCheck(void) { LCD_DATA_PORT = 0xFF; LCD_RS = LCD_SEL_CMD; LCD_RW = LCD_IO_READ; LCD_EN = HIGH; while(LCD_BF == HIGH); LCD_EN = LOW; } static void LCD_DataWr(uint8 data) { LCD_BusyCheck(); LCD_RS = LCD_SEL_DATA; LCD_RW = LCD_IO_WRITE; LCD_DATA_PORT = data; LCD_EN = HIGH; asm("nop"); LCD_EN = LOW; } static void LCD_CmdWr(uint8 cmd) { LCD_BusyCheck(); LCD_RS = LCD_SEL_CMD; LCD_RW = LCD_IO_WRITE; LCD_DATA_PORT = cmd; LCD_EN = HIGH; asm("nop"); LCD_EN = LOW; } static void LCD_CursorSet(uint8 row, uint8 col) { 略 } #endif
  43. 43. 將delayms()放到common driver 43 /************************************************************************* Filename: hal_drivers.h Revised: $Date: 2013-10-18 14:52 $ Revision: $Revision: $ Description: This file contains the interface to the Drivers service. **************************************************************************/ #ifndef HAL_DRIVER_H #define HAL_DRIVER_H /************************************************************************* * FUNCTIONS - API *************************************************************************/ extern void delayms(uint8 time); /* * Initialize HW */ extern void HalDriverInit (void); /************************************************************************* *************************************************************************/ #endif D:MySimpSystemhalinclude
  44. 44. 44 D:MySimpSystemhalcommon /**************************************************************************** Filename: hal_drivers.c Revised: $Date: 20103-10-19 17:00 $ Revision: $Revision: $ Description: This file contains the common functions used by the driver *****************************************************************************/ /******** INCLUDES *************/ #include "hal_types.h" #include "hal_drivers.h" #include "hal_lcd.h" /******** FUNCTIONS – API **********/ /*************************************************** * @fn delayms * @brief delay with ms * @param time = 0 ~ 255, the maximum delay is 255 ms * @return None ***************************************************/ void delayms(uint8 time) { uint8 n; while(time>0) { n = 162; while(n>0) n--; time --; } } /***************************************************** * @fn HalDriverInit * @brief Initialize HW * @param None * @return None ******************************************************/ void HalDriverInit (void) { #if (defined HAL_LCD) && (HAL_LCD == TRUE) LCD_Init(2, 16); #endif }
  45. 45. 修改hal_board_cfg.h 45 /*************************************************************** Filename: hal_board_cfg.h Revised: $Date: 2013-10-19 $ Revision: $Revision: $ Description: Declarations for the JC51B Development Board. ***************************************************************/ #ifndef HAL_BOARD_CFG_H #define HAL_BOARD_CFG_H /* ------------- Includes ------------*/ #include "hal_mcu.h" #include "hal_defs.h" #include "hal_types.h" #include "hal_lcd.h" /* -------- Driver Configuration -------- */ /* Set to TRUE enable LCD usage, FALSE disable it */ #ifndef HAL_LCD #define HAL_LCD TRUE #endif #endif /********************************************************************************** */
  46. 46. 準備加入按鍵驅動程式 46  先修改一下hal_board_cfg.h的內容 /*************************************************************** Filename: hal_board_cfg.h Revised: $Date: 2013-10-19 $ Revision: $Revision: $ Description: Declarations for the JC51B Development Board. ***************************************************************/ #ifndef HAL_BOARD_CFG_H #define HAL_BOARD_CFG_H /* ------------- Includes ------------*/ #include "hal_mcu.h" #include "hal_defs.h" #include "hal_types.h" #include "hal_lcd.h" #include "hal_key.h" /* ---- Push Button Configuration ----*/ #define ACTIVE_LOW ! /* double negation forces result to be '1' */ #define ACTIVE_HIGH !! /* BTN1 */ #define PUSH1_BV BV(2) #define PUSH1_SBIT P3_bit.P3_2 // INT0 #define PUSH1_POLARITY ACTIVE_LOW /* BTN2 */ #define PUSH2_BV BV(3) #define PUSH2_SBIT P3_bit.P3_3 // INT1 #define PUSH2_POLARITY ACTIVE_LOW /* BTN3 */ #define PUSH3_BV BV(4) #define PUSH3_SBIT P3_bit.P3_4 // T0 #define PUSH3_POLARITY ACTIVE_LOW /* BTN4 */ #define PUSH4_BV BV(5) #define PUSH4_SBIT P3_bit.P3_5 // T1 #define PUSH4_POLARITY ACTIVE_LOW
  47. 47. 47 /* ----- Macros ------*/ // ---- Debounce ---- // #define HAL_DEBOUNCE(expr) { int i; for (i=0; i<500; i++) { if (!(expr)) i = 0; } } // ---- Push Buttons ---- // #define HAL_PUSH_BUTTON1() (PUSH1_POLARITY (PUSH1_SBIT)) #define HAL_PUSH_BUTTON2() (PUSH2_POLARITY (PUSH2_SBIT)) #define HAL_PUSH_BUTTON3() (PUSH3_POLARITY (PUSH3_SBIT)) #define HAL_PUSH_BUTTON4() (PUSH4_POLARITY (PUSH4_SBIT)) /* -------- Driver Configuration -------- */ /* Set to TRUE enable LCD usage, FALSE disable it */ #ifndef HAL_LCD #define HAL_LCD TRUE #endif /* Set to TRUE enable KEY usage, FALSE disable it */ #ifndef HAL_KEY #define HAL_KEY TRUE #endif #endif /********************************************************************************** */
  48. 48. 加入按鍵的驅動程式 48 /********************************************************************** Filename: hal_key.h Revised: $Date: 2013-10-19 17:51 $ Revision: $Revision: $ Description: This file contains the interface to the KEY Service. ***********************************************************************/ #ifndef HAL_KEY_H #define HAL_KEY_H /****** INCLUDES ******/ #include "hal_board.h" /****** CONSTANTS *****/ /* Interrupt option - Enable or disable */ #define HAL_KEY_INTERRUPT_DISABLE 0x00 #define HAL_KEY_INTERRUPT_ENABLE 0x01 /* Switches (keys) */ #define HAL_KEY_SW_1 0x01 // Button 1 (INT0) #define HAL_KEY_SW_2 0x02 // Button 2 (INT1) #define HAL_KEY_SW_3 0x04 // Button 3 (T0) #define HAL_KEY_SW_4 0x08 // Button 4 (T1) /******* GLOBAL VARIABLES *******/ extern bool Hal_KeyIntEnable; /******** FUNCTIONS – API *********/ /* Initialize the Key Service */ extern void HalKeyInit(void); /* Configure the Key Service */ extern void HalKeyConfig(bool interruptEnable); /* Read the Key status */ extern uint8 HalKeyRead(void); /********************************** *************************************/ #endif D:MySimpSystemhalinclude
  49. 49. 49 /********************************************* Filename: hal_key.c Revised: $Date: 2013-10-19 22:27 $ Revision: $Revision: $ Description: HAL KEY Service. **********************************************/ /******* INCLUDES **********/ #include "hal_mcu.h" #include "hal_defs.h" #include "hal_types.h" #include "hal_board.h" #include "hal_drivers.h" #include "hal_key.h" #if (defined HAL_KEY) && (HAL_KEY == TRUE) /******* CONSTANTS *******/ #define HAL_KEY_NO_EDGE 0 #define HAL_KEY_FALLING_EDGE 1 #define HAL_KEY_DEBOUNCE_VALUE 25 /* CPU port interrupt edge control and flag*/ #define HAL_KEY_CPU_TCON TCON /* CPU port interrupt enable/disable*/ #define HAL_KEY_CPU_IE IE D:MySimpSystemhaltargetJC51B /********* Key 1 ************/ /* SW_1 is at P3.2 */ #define HAL_KEY_SW_1_PORT PUSH1_SBIT /* edge interrupt */ #define HAL_KEY_SW_1_EDGEBIT BV(0) // TCON => Bit0 #define HAL_KEY_SW_1_EDGE HAL_KEY_FALLING_EDGE /* SW_1 interrupts, INT0 IE bit and flag */ #define HAL_KEY_SW_1_IEBIT BV(0) #define HAL_KEY_SW_1_IFG TCON_bit.IE0 /********* Key 2 ************/ /* SW_2 is at P3.3 */ #define HAL_KEY_SW_2_PORT PUSH2_SBIT /* edge interrupt */ #define HAL_KEY_SW_2_EDGEBIT BV(2) // TCON => Bit2 #define HAL_KEY_SW_2_EDGE HAL_KEY_FALLING_EDGE /* SW_2 interrupts, INT1 IE bit and flag */ #define HAL_KEY_SW_2_IEBIT BV(2) #define HAL_KEY_SW_2_IFG TCON_bit.IE1 /********* Key 3 ************/ /* SW_3 is at P3.4, Key3 has no interrupt */ #define HAL_KEY_SW_3_PORT PUSH3_SBIT /********* Key 4 ************/ /* SW_4 is at P3.5, Key4 has no interrupt */ #define HAL_KEY_SW_4_PORT PUSH4_SBIT
  50. 50. /******** GLOBAL VARIABLES ********/ static uint8 HalKeyConfigured; /* interrupt enable/disable flag */ bool Hal_KeyIntEnable; /******* FUNCTIONS – API ************/ /***************************************** * @fn HalKeyInit * @brief Initialize Key Service * @param none * @return None *****************************************/ void HalKeyInit( void ) { HAL_KEY_SW_1_PORT = 1; // make it as an input HAL_KEY_SW_2_PORT = 1; // make it as an input HAL_KEY_SW_3_PORT = 1; // make it as an input HAL_KEY_SW_4_PORT = 1; // make it as an input /* Start with key is not configured */ HalKeyConfigured = FALSE; } void HalKeyConfig (bool interruptEnable) { /* Enable/Disable Interrupt */ Hal_KeyIntEnable = interruptEnable; // Hal_KeyIntEnable is a global var. /* Determine if interrupt is enable or not! Interrupt is only for Key1 and Key2 */ if (Hal_KeyIntEnable) { /********* Key 1 ************/ /* Rising/Falling edge configuration */ HAL_KEY_CPU_TCON &= ~(HAL_KEY_SW_1_EDGEBIT); /* For falling edge, the bit must be set. */ #if (HAL_KEY_SW_1_EDGE == HAL_KEY_FALLING_EDGE) HAL_KEY_CPU_TCON |= HAL_KEY_SW_1_EDGEBIT; #endif /* Interrupt configuration: */ HAL_KEY_CPU_IE |= HAL_KEY_SW_1_IEBIT; HAL_KEY_SW_1_IFG = 0; /********* Key 2 ************/ /* Rising/Falling edge configuration */ HAL_KEY_CPU_TCON &= ~(HAL_KEY_SW_2_EDGEBIT); /* For falling edge, the bit must be set. */ #if (HAL_KEY_SW_2_EDGE == HAL_KEY_FALLING_EDGE) HAL_KEY_CPU_TCON |= HAL_KEY_SW_2_EDGEBIT; #endif /* Interrupt configuration: */ HAL_KEY_CPU_IE |= HAL_KEY_SW_2_IEBIT; HAL_KEY_SW_2_IFG = 0; /********* Key 3 ************/ /* Key3 has no interrupt */ /********* Key 4 ************/ /* Key4 has no interrupt */ 50
  51. 51. } else { /* Interrupts NOT enabled */ HAL_KEY_CPU_IE &= ~(HAL_KEY_SW_1_IEBIT); HAL_KEY_SW_1_IFG = 0; HAL_KEY_CPU_IE &= ~(HAL_KEY_SW_2_IEBIT); HAL_KEY_SW_2_IFG = 0; } /* Key now is configured */ HalKeyConfigured = TRUE; } /********************************************* * @fn HalKeyRead * @brief Read the current value of a key * @param None * @return keys - current keys status ********************************************/ uint8 HalKeyRead ( void ) { uint8 keys = 0; if (HAL_PUSH_BUTTON1()) { HAL_DEBOUNCE(!HAL_PUSH_BUTTON1()); keys |= HAL_KEY_SW_1; } if (HAL_PUSH_BUTTON2()) { HAL_DEBOUNCE(!HAL_PUSH_BUTTON2()); keys |= HAL_KEY_SW_2; } if (HAL_PUSH_BUTTON3()) { HAL_DEBOUNCE(!HAL_PUSH_BUTTON3()); keys |= HAL_KEY_SW_3; } /****** INTERRUPT SERVICE ROUTINE *******/ /**************************************** * @fn halKeySW1Isr * @brief SW1 ISR * @param * @return ***************************************/ HAL_ISR_FUNCTION( halKeySW1Isr, extern0 ) { HAL_ENTER_ISR(); //Clear the CPU interrupt flag HAL_KEY_SW_1_IFG = 0; HAL_EXIT_ISR(); } /**************************************** * @fn halKeySW2Isr * @brief SW2 ISR * @param * @return ***************************************/ HAL_ISR_FUNCTION( halKeySW2Isr, extern1 ) { HAL_ENTER_ISR(); //Clear the CPU interrupt flag HAL_KEY_SW_2_IFG = 0; HAL_EXIT_ISR(); } 51
  52. 52. 52 #else void HalKeyInit(void) { } void HalKeyConfig(bool interruptEnable) { } uint8 HalKeyRead(void) { return 0; } #endif /* HAL_KEY */ /****************************************************************** ******************************************************************/
  53. 53. 加入Library Path 53  現在你已經準備好幾樣東西,讓我們再複習一下 hal_mcu.h hal_types.h hal_board_cfg.h hal_defs.h hal_drivers.h hal_board.h hal_lcd.h hal_key.h hal_drviers.c hal_lcd.c hal_key.c
  54. 54. 在進行RTC實驗之前 54  我們現在有按鍵跟LCD驅動程式,何不寫一個應用 程式,完成如exercise4-03.c的進度條顯示程式。 D:MySimpSystemProjectsMyAPP1Source #include "hal_types.h" #include "hal_drivers.h" #include "hal_board_cfg.h" #include "MyAPP1.h" void main() { uint8 i, percent_bar; char num[4]; char *str1 = "Dynamic Show"; HalDriverInit(); LCD_DispHorBarInit(); LCD_DispStr(0, 0, str1); while(1) { if (HalKeyRead()==HAL_KEY_SW_1) { LCD_ClrLine(0); LCD_ClrLine(1); for(i=0;i<101;i++) { num[0] = (i/100)+0x30; num[1] = ((i/10)%10)+0x30; num[2] = (i%10)+0x30; num[3] = 0x25; if(num[0]==0x30) { LCD_DispChar(0, 0, ' '); if(num[1]==0x30) LCD_DispChar(0, 1, ' '); else LCD_DispChar(0, 1, num[1]); } else { LCD_DispChar(0, 0, num[0]); LCD_DispChar(0, 1, num[1]); } LCD_DispChar(0, 2, num[2]); LCD_DispChar(0, 3, num[3]); percent_bar = (i*100/125); LCD_DispHorBar(1, 0, percent_bar); delayms(200); } } } }
  55. 55. 顯現電路板設定組態檔的威力  將driver與硬體I/O相關的設定移到hal_borad_cfg.h #define LCD_RW P1_bit.P1_1 #define LCD_EN P3_bit.P3_4 #define LCD_RS P3_bit.P3_5 #define LCD_BF P0_bit.P0_7 #define LCD_DATA_PORT P0 /**************************************************** Filename: hal_board_cfg.h *****************************************************/ #ifndef HAL_BOARD_CFG_H 略 /* BTN1 */ #define PUSH1_BV BV(2) #define PUSH1_SBIT P3_bit.P3_2 // INT0 #define PUSH1_POLARITY ACTIVE_LOW /* BTN2 */ #define PUSH2_BV BV(3) #define PUSH2_SBIT P3_bit.P3_3 // INT1 #define PUSH2_POLARITY ACTIVE_LOW /* BTN3 */ #define PUSH3_BV BV(4) #define PUSH3_SBIT P3_bit.P3_4 // T0 #define PUSH3_POLARITY ACTIVE_LOW /* BTN4 */ #define PUSH4_BV BV(5) #define PUSH4_SBIT P3_bit.P3_5 // T1 #define PUSH4_POLARITY ACTIVE_LOW /* -- LCD I/O Configuration --*/ #define LCD_RW P1_bit.P1_1 #define LCD_EN P3_bit.P3_4 #define LCD_RS P3_bit.P3_5 #define LCD_BF P0_bit.P0_7 #define LCD_DATA_PORT P0 55
  56. 56. 練習3: 撰寫API手冊 (以LCD Driver為例) 56
  57. 57. 57
  58. 58. 58
  59. 59. 59
  60. 60. 60
  61. 61. 61
  62. 62. 為RTC準備什麼 62  3-wire通訊介面的驅動程式  DS1302的驅動程式  寫完後將他們一一加入project的group  修改hal_board_cfg.h  寫出RTC的應用程式
  63. 63. 練習4: 加入3-wire通訊介面Driver 63 /************************************************************************* Filename: hal_triwire.h Revised: $Date: 2013-10-18 $ Revision: $Revision: $ Description: This file contains the interface to the 3-Wire Service. *************************************************************************/ #ifndef HAL_TRIWIRE_H #define HAL_TRIWIRE_H /**** INCLUDES *****/ #include "hal_board.h" /**** CONSTANTS ****/ /* 3-Wire delay */ #define TriWireDELAY 10 /**** FUNCTIONS – API ****/ /* 3-wire interface: write a byte to the bus */ extern void TriWire_WriteByte(uint8 output_data); /* 3-wire interface: read a byte from the bus */ extern uint8 TriWire_ReadByte(void); /* 3-wire interface: write data to the device register */ extern void TriWire_Write(uint8 Reg_Addr, uint8 Reg_Data) /* 3-wire interface: read data from the device register */ extern uint8 TriWire_Read(uint8 Reg_Addr) /************************************************************************ ************************************************************************/ #endif
  64. 64. 加入3-wire的driver: hal_triwire.c 64 /********************************************************************** Filename: hal_triwire.c Revised: $Date: 2013-10-18 21:07 $ Revision: $Revision: $ Description: This file contains the interface to the 3-wire driver. **********************************************************************/ /********* INCLUDES ***********/ #include "hal_board_cfg.h" #include "hal_defs.h" #include "hal_types.h“ #include "hal_drivers.h" #include "hal_triwire.h" /********* LOCAL FUNCTIONS *******/ /* 3-wire interface: write a byte to the bus */ //void TriWire_WriteByte(uint8 output_data); /* 3-wire interface: read a byte from the bus */ //uint8 TriWire_ReadByte(void);
  65. 65. /********************************************************* * @fn TriWire_WriteByte * @brief Write 1-byte data to the bus * @param output_data: The data byte to write on the bus * @return None *********************************************************/ void TriWire_WriteByte(uint8 output_data) { uint8 index; for(index = 0; index < 8; index++) { TriWire_SCLK = LOW; if(output_data & 0x01) // Check LSB bit, LSB goes first TriWire_IO = HIGH; else TriWire_IO = LOW; delay_time(TriWireDELAY); TriWire_SCLK = HIGH; // Write at this transition delay_time(TriWireDELAY); output_data = output_data >> 1; } } /************************************************** * @fn TriWire_ReadByte * @brief Read 1-byte data from the bus * @param None * @return The read-in data byte ***************************************************/ uint8 TriWire_ReadByte(void) { uint8 index; uint8 input_data = 0x00; for(index = 0; index < 8; index++) { input_data = input_data >> 1; TriWire_SCLK = LOW; // Read at this transition delay_time(TriWireDELAY); if(TriWire_IO) // Check LSB bit, LSB comes first input_data |= 0x80; else input_data |= 0x00; TriWire_SCLK = HIGH; delay_time(TriWireDELAY); } return(input_data); } 65
  66. 66. 66 /***************************************************************** * @fn TriWire_Write * @brief Write data to the register on a 3-wire device * @param Reg_Addr: Register address, Reg_Data: Data to write-to * @return None ****************************************************************/ void TriWire_Write(uint8 Reg_Addr, uint8 Reg_Data) { TriWire_RST = LOW; TriWire_SCLK = LOW; TriWire_RST = HIGH; delay_time(TriWireDELAY); TriWire_WriteByte(Reg_Addr); TriWire_WriteByte(Reg_Data); TriWire_SCLK = HIGH; TriWire_RST = LOW; } /***************************************************************** * @fn TriWire_Read * @brief Read data from the register on a 3-wire device * @param Reg_Addr: Register address * @return Data: The read-in data byte@Reg_Addr ****************************************************************/ uint8 TriWire_Read(uint8 Reg_Addr) { uint8 Data; TriWire_RST = LOW; TriWire_SCLK = LOW; TriWire_RST = HIGH; delay_time(TriWireDELAY); TriWire_WriteByte(Reg_Addr|0x01); // Command - Read Data = TriWire_ReadByte(); TriWire_SCLK = HIGH; TriWire_RST = LOW; return(Data); } #if (HAL_TRIWIRE == TRUE) … #endif
  67. 67. Add file與修改hal_board_cfg.h 67 /* ---------------------------------------------- * 3-Wire Port Configuration * ---------------------------------------------- */ #define TriWire_SCLK P1_bit.P1_4 #define TriWire_IO P1_bit.P1_2 #define TriWire_RST P1_bit.P1_3
  68. 68. 測試驅動程式 (I) 68  寫一個應用程式,測試3-wire的驅動程式 #include "MyAPP1.h" void main() { uint8 read_keys; HalDriverInit(); while(1) { read_keys = 0x00; read_keys = HalKeyRead(); switch(read_keys) { case HAL_KEY_SW_1: TriWire_WriteByte(0x35); break; case HAL_KEY_SW_2: TriWire_ReadByte(); break; case HAL_KEY_SW_3: TriWire_Write(0xA2, 0xB4); break; case HAL_KEY_SW_4: TriWire_Read(0x37); break; } } } /* --------------------------------- * Driver Configuration * --------------------------------- */ /* Set to TRUE enable LCD usage, FALSE disable it */ #ifndef HAL_LCD #define HAL_LCD FALSE #endif /* Set to TRUE enable KEY usage, FALSE disable it */ #ifndef HAL_KEY #define HAL_KEY TRUE #endif /* Set to TRUE enable 3-wire usage, FALSE disable it */ #ifndef HAL_TRIWIRE #define HAL_TRIWIRE TRUE #endif
  69. 69. 測試驅動程式 (II) 69 case HAL_KEY_SW_1: TriWire_WriteByte(0x35); break;
  70. 70. 測試驅動程式 (III) 70 case HAL_KEY_SW_2: TriWire_ReadByte(); break;
  71. 71. 測試驅動程式 (IV) 71 case HAL_KEY_SW_3: TriWire_Write(0xA2, 0xB4); break;
  72. 72. 測試驅動程式 (V) 72 case HAL_KEY_SW_4: TriWire_Read(0x37); break;
  73. 73. 加入DS1302 RTC驅動程式 /************************************************************* Filename: hal_ds1302.h Revised: $Date: 2013-10-18 $ Revision: $Revision: $ Description: This file contains the driver of DS1302 RTC. *************************************************************/ #ifndef HAL_DS1302_H #define HAL_DS1302_H /***** INCLUDES ******/ #include "hal_board.h" /***** CONSTANTS ******/ // DS1302 Register Address #define DS1302_SECOND 0x80 #define DS1302_MINUTE 0x82 #define DS1302_HOUR 0x84 #define DS1302_DATE 0x86 #define DS1302_MONTH 0x88 #define DS1302_WEEKDAY 0x8A #define DS1302_YEAR 0x8C #define DS1302_WP 0x8E #define DS1302_TCS 0x90 // DS1302 Register Mask #define REG_MASK_SECOND 0x70 #define REG_MASK_MINUTE 0x30 #define REG_MASK_HOUR 0x30 #define REG_MASK_DATE 0x30 #define REG_MASK_MONTH 0x10 #define REG_MASK_WEEKDAY 0x00 #define REG_MASK_YEAR 0xF0 #define REG_MASK_HOUR_MODE 0xA0 #define REG_MASK_CH 0x80 // DS1302 Write Protection #define DS1302_WR_ON 0x00 #define DS1302_WR_OFF 0x80 #define DS1302_START 0x7F /***** TYPEDEFS ******/ typedef struct __SYSTEMTIME__ { uint8 Second; uint8 Minute; uint8 Hour; uint8 Hourmode; uint8 Date; uint8 Weekday; uint8 Month; uint8 Year; uint8 DateString[11]; uint8 WeekdayString[4]; uint8 TimeString[9]; }SYSTEMTIME; /***** FUNCTIONS – API ******/ extern void DS1302_Init(void); extern void DS1302_ReadTime(SYSTEMTIME *Time); extern void DS1302_WriteTime(SYSTEMTIME *Time); #endif 73
  74. 74. 74 /********************************************* Filename: hal_ds1302.c Revised: $Date: 2013-10-18 21:36 $ Revision: $Revision: $ ********************************************/ /***** INCLUDES ******/ #include "hal_board_cfg.h" #include "hal_defs.h" #include "hal_types.h" #include "hal_drivers.h" #include "hal_triwire.h" #include "hal_ds1302.h" /***** LOCAL FUNCTIONS ******/ uint8 FormatReg2Dec(uint8 reg_data, uint8 reg_mask); uint8 FormatDec2Reg(uint8 dec_data); void DateToStr(SYSTEMTIME *Time); void TimeToStr(SYSTEMTIME *Time); /*********************************************** * @fn DS1302_Init * @brief Initialize DS1302 * @param None * @return None ***********************************************/ void DS1302_Init(void) { delayms(2); uint8 Clock_halt = TriWire_Read(DS1302_SECOND+1) & REG_MASK_CH; if(Clock_halt) { TriWire_Write(DS1302_WP , DS1302_WR_ON); // Allow write // Write initial date and time: 2013/11/12, TUE, 23:59:55 TriWire_Write(DS1302_YEAR , 0x13); TriWire_Write(DS1302_MONTH , 0x11); // month: 07 TriWire_Write(DS1302_DATE , 0x12); // date: 25 TriWire_Write(DS1302_WEEKDAY, 0x02); // weekday TriWire_Write(DS1302_HOUR , 0x23); // 23 (HR) TriWire_Write(DS1302_MINUTE , 0x59); // 59 (Min) TriWire_Write(DS1302_SECOND , 0x55); // 55 (Sec) TriWire_Write(DS1302_WP , DS1302_WR_OFF); // Write prohibited } }
  75. 75. /************************************************************************************************* * @fn DS1302_ReadTime * @brief Read current time from DS1302, the read values are stored in a SYSTIME struct variable * @param SYSTEMTIME *Time: Pointer to the SYSTEMTIME struct variable * @return None ************************************************************************************************/ void DS1302_ReadTime(SYSTEMTIME *Time) { uint8 ReadValue; ReadValue = TriWire_Read(DS1302_SECOND+1); // When read, use (defined address+1) Time->Second = FormatReg2Dec(ReadValue, REG_MASK_SECOND); ReadValue = TriWire_Read(DS1302_MINUTE+1); Time->Minute = FormatReg2Dec(ReadValue, REG_MASK_MINUTE); ReadValue = TriWire_Read(DS1302_HOUR+1); Time->Hour = FormatReg2Dec(ReadValue, REG_MASK_HOUR); Time->Hourmode = ReadValue & REG_MASK_HOUR_MODE; ReadValue = TriWire_Read(DS1302_DATE+1); Time->Date = FormatReg2Dec(ReadValue, REG_MASK_DATE); ReadValue = TriWire_Read(DS1302_MONTH+1); Time->Month = FormatReg2Dec(ReadValue, REG_MASK_MONTH); ReadValue = TriWire_Read(DS1302_WEEKDAY+1); Time->Weekday = FormatReg2Dec(ReadValue, REG_MASK_WEEKDAY); ReadValue = TriWire_Read(DS1302_YEAR+1); Time->Year = FormatReg2Dec(ReadValue, REG_MASK_YEAR); DateToStr(Time); TimeToStr(Time); } 75
  76. 76. 76 /******************************************************************************* * @fn DS1302_WriteTime * @brief Write time to DS1302 * @param SYSTEMTIME *Time: Pointer to the SYSTEMTIME struct variable * @return None ******************************************************************************/ void DS1302_WriteTime(SYSTEMTIME *Time) { TriWire_Write(DS1302_WP , DS1302_WR_ON); TriWire_Write(DS1302_YEAR , FormatDec2Reg(Time->Year) ); TriWire_Write(DS1302_MONTH , FormatDec2Reg(Time->Month) ); TriWire_Write(DS1302_DATE , FormatDec2Reg(Time->Date) ); TriWire_Write(DS1302_WEEKDAY, FormatDec2Reg(Time->Weekday)); TriWire_Write(DS1302_HOUR , FormatDec2Reg(Time->Hour) ); TriWire_Write(DS1302_MINUTE , FormatDec2Reg(Time->Minute) ); TriWire_Write(DS1302_SECOND , FormatDec2Reg(Time->Second) ); DateToStr(Time); TimeToStr(Time); TriWire_Write(DS1302_WP , DS1302_WR_OFF); } /**************************************************************************** * LOCAL FUNCTIONS /**************************************************************************** * @fn FormatReg2Dec * @brief Convert the register data into decimal * @param reg_data: the stored data in DS1302, reg_mask: mask of that value * @return DecValue: The converted decimal value ****************************************************************************/ uint8 FormatReg2Dec(uint8 reg_data, uint8 reg_mask) { uint8 DecValue; DecValue = ((reg_data & reg_mask) >> 4)*10 + (reg_data & 0x0F); return(DecValue); }
  77. 77. /******************************************************************** * @fn FormatDec2Reg * @brief Convert the decimal value in to register data format * @param dec_data: the decimal value to store * @return RegValue: the formatted register data *******************************************************************/ uint8 FormatDec2Reg(uint8 dec_data) { uint8 RegValue; RegValue = (dec_data/10)*16 + dec_data%10; return(RegValue); } /******************************************************************* * @fn DateToStr * @brief Convert Date (year, month, date, weekday) into string * @param *Time: Pointer to the struct of current time * @return None ******************************************************************/ void DateToStr(SYSTEMTIME *Time) { uint8 *WeekdayTable[7] = {"Mon", "Tue", "Wen", "Thu", "Fri", "Sat", "Sun"}; Time->DateString[0] = '2'; Time->DateString[1] = '0'; Time->DateString[2] = Time->Year/10 + 0x30; // '0' : ASCII = 0x30 Time->DateString[3] = Time->Year%10 + 0x30; Time->DateString[4]='-'; Time->DateString[5] = Time->Month/10 + 0x30; Time->DateString[6] = Time->Month%10 + 0x30; Time->DateString[7]='-'; Time->DateString[8] = Time->Date/10 + 0x30; Time->DateString[9] = Time->Date%10 + 0x30; Time->DateString[10] = '0'; Time->WeekdayString[0] = *(WeekdayTable[(Time->Weekday%10)-1] + 0); Time->WeekdayString[1] = *(WeekdayTable[(Time->Weekday%10)-1] + 1); Time->WeekdayString[2] = *(WeekdayTable[(Time->Weekday%10)-1] + 2); Time->WeekdayString[3] = '0'; } 77
  78. 78. 78 /***************************************************************************** * @fn TimeToStr * @brief Convert Time (hour, minute, second) into string * @param *Time: Pointer to the struct of current time * @return None ****************************************************************************/ void TimeToStr(SYSTEMTIME *Time) { Time->TimeString[0] = Time->Hour/10 + 0x30; // '0' : ASCII = 0x30 Time->TimeString[1] = Time->Hour%10 + 0x30; Time->TimeString[2] = ':'; Time->TimeString[3] = Time->Minute/10 + 0x30; Time->TimeString[4] = Time->Minute%10 + 0x30; Time->TimeString[6] = Time->Second/10 + 0x30; Time->TimeString[7] = Time->Second%10 + 0x30; Time->TimeString[8] = '0'; } #if (HAL_DS1302 == TRUE) … #endif
  79. 79. 修改hal_board_cfg.h 79 /************************************************************************************************** Filename: hal_board_cfg.h Revised: $Date: 2013-11-2 $ Revision: $Revision: $ Description: Declarations for the JC51B Development Board. **************************************************************************************************/ #ifndef HAL_BOARD_CFG_H #define HAL_BOARD_CFG_H /* ------- Includes ---------*/ #include "hal_mcu.h" #include "hal_defs.h" #include "hal_types.h" #include "hal_lcd.h" #include "hal_key.h" #include "hal_triwire.h" #include "hal_ds1302.h" **** 略 ***** /* ------ 3-Wire Port Configuration ------*/ #define TriWire_SCLK P1_bit.P1_4 #define TriWire_IO P1_bit.P1_2 #define TriWire_RST P1_bit.P1_3 /* --------- Driver Configuration -------------- */ /* Set to TRUE enable LCD usage, FALSE disable it */ #ifndef HAL_LCD #define HAL_LCD TRUE #endif /* Set to TRUE enable KEY usage, FALSE disable it */ #ifndef HAL_KEY #define HAL_KEY TRUE #endif /* Set to TRUE enable 3-wire usage, FALSE disable it */ #ifndef HAL_TRIWIRE #define HAL_TRIWIRE TRUE #endif /* Set to TRUE enable DS1302 RTC usage, FALSE disable it */ #ifndef HAL_DS1302 #define HAL_DS1302 TRUE #endif
  80. 80. 修改hal_drivers.c的HalDriverInit() 80 /************************************************************************************** * @fn Hal_DriverInit * @brief Initialize HW - These need to be initialized before anyone. * @param None * @return None ************************************************************************************/ void HalDriverInit (void) { #if (defined HAL_LCD) && (HAL_LCD == TRUE) LCD_Init(2, 16); #endif #if (defined HAL_KEY) && (HAL_KEY == TRUE) HalKeyInit(); HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE); #endif #if (defined HAL_DS1302) && (HAL_DS1302 == TRUE) DS1302_Init(); #endif }
  81. 81. 練習5: 寫一支電子時鐘應用程式 81 #include "MyAPP1.h" SYSTEMTIME currentTime; /* SYSTEMTIME currentTime = { .Second = 30, .Minute = 50, .Hour = 22, .Hourmode = 0, .Date = 2, .Weekday = 6, .Month = 11, .Year = 13, }; */ void main() { HalDriverInit(); // DS1302_WriteTime(&currentTime); while(1) { DS1302_ReadTime(&currentTime); LCD_DispStr(0, 0, currentTime.DateString); LCD_DispStr(0, 12, currentTime.WeekdayString); LCD_DispStr(1, 0, currentTime.TimeString); } }
  82. 82. Lab12: DS18B20溫度感測器 82
  83. 83. DS18B20溫度感測器 83  DS18B20是一個數位溫度感測器,它可以提供9~12位元 的攝氏溫度輸出,而且可以設定超溫警告閥值。它使 用一條數據傳輸線(1-Wire)介面與MCU進行雙向通訊。  電壓範圍:3.0~5.5V  溫度範圍:-55oC~+125oC。-10~+85oC時精度為±0.5oC  解析度為9~12位元,對應的 可分辨溫度量為 0.5oC、0.25oC、 0.125oC和 0.0625oC。在9位元 解析度時,最多在93.75ms內 能把溫度轉換為數位值;在12 位元解析度時,最多在750ms 內把溫度值轉換為數位值。
  84. 84. DS18B20架構說明 84
  85. 85. DS18B20的記憶體配置 85
  86. 86. 與DS18B20進行通訊 86
  87. 87. DS1820B的指令集 87 指令 指令碼 說 明 搜尋ROM 0xF0 確定掛在同一bus上 DS1820 的個數和識別 64 位元ROM地址。為操作各裝置作好準備。 讀ROM 0x33 讀取DS1820 ROM中的64位元ROM位址 匹配ROM 0x55 發出此命令後,接著發出 64 位元ROM位址,使對應的DS1820作出回應,為下一步對 該其讀寫作準備。 跳過ROM 0xCC 忽略 64 位 ROM 地址,直接向 DS1820 下達溫度變換命令。 警告搜索 0xEC 執行後只有溫度超過設定值上限或下限的晶片才做出回應。 指令 指令碼 說 明 溫度轉換 0x44 執行溫度轉換,結果將存入內部9位元組RAM中。 寫入暫存器 0x4E 向RAM的2, 3, 4位元組寫上、下限溫度資料、組態,該命令之後緊接3位元組的資料。 讀取暫存器 0xBE 讀取內部RAM中9位元組的內容。 複製暫存器 0x48 將RAM中第3, 4位元組的內容複製到EEPROM中。 Recall EEPROM 0xB8 將EEPROM中的內容還原到RAM中的第3 , 4位元組。 讀取供電方式 0xB4 寄生供電時DS1820發回 0,外接電源發回 1 。
  88. 88. Read/Write時序圖 88
  89. 89. 使用注意事項 89  DS1820與MCU使用串列通訊,因此對DS1820進行讀寫時必須嚴格 保證讀寫時序,否則將無法讀取測溫結果。  實際應用中1-Wire bus上所掛DS1820數量並非任意多個,當數量超 過8個時就需要解決MCU的匯流排驅動問題。  連接DS1820的匯流排電纜有長度限制,經驗中使用一般電線長度 超過50m時,讀取的測溫資料將發生錯誤。使用雙絞線帶遮罩電 纜時,正常通訊距離可達150m。  DS1820測溫程式中,向DS1820發出溫度轉換命令後,程式總要等 待DS1820的返回訊號,一旦某個DS1820接觸不好或斷線,當程式 讀該DS1820時,將沒有返回訊號,程式進入閉迴路。這一點在進 行DS1820硬體連接和軟體設計時也要給予一定的重視。 測溫電纜 線建議採用遮罩4芯雙絞線,其中一對線接地線與訊號線,另一組 接VCC和地線,遮罩層在源端單點接地。
  90. 90. /************************************************* Filename: hal_onewire.c Revised: $Date: 2013-11-5 21:07 $ **************************************************/ /****** INCLUDES ******/ #include "hal_board_cfg.h" #include "hal_defs.h" #include "hal_types.h" #include "hal_drivers.h" #include "hal_onewire.h" /****** CONSTANTS ******/ /* 1-Wire delay*/ #define OneWireDELAY_Write 6 #define OneWireDELAY_Read 4 /************************************************ * @fn OneWire_WriteByte * @brief Write 1-byte data to the bus ***********************************************/ void OneWire_WriteByte(uint8 output_data) { uint8 index; for(index = 0; index < 8; index++) { OneWire_DQ = LOW; OneWire_DQ = output_data & 0x01; // 5us delay_time(OneWireDELAY_Write); // 76us OneWire_DQ = HIGH; output_data = output_data >> 1; } } 1-Wire通訊介面驅動程式 90 /*********************************************** Filename: hal_onewire.h Revised: $Date: 2013-11-6 $ Revision: $Revision: $ Description: This file contains the interface to the 1-Wire service. ***********************************************/ #ifndef HAL_ONEWIRE_H #define HAL_ONEWIRE_H /****** INCLUDES ******/ #include "hal_board.h“ /****** FUNCTIONS - API ******/ /* 1-wire interface: write a byte to the bus */ extern void OneWire_WriteByte(uint8 output_data); /* 1-wire interface: read a byte from the bus */ extern uint8 OneWire_ReadByte(void); /* 1-wire interface: Reset devices on the bus */ extern void OneWire_BusReset(void); #endif
  91. 91. 91 /******************************************** * @fn OneWire_ReadByte * @brief Read 1-byte data from the bus * @param None * @return The read-in data byte *******************************************/ uint8 OneWire_ReadByte(void) { uint8 index; uint8 input_data = 0x00; for(index = 0; index < 8; index++) { OneWire_DQ = LOW; input_data = input_data >> 1; // takes 5us OneWire_DQ = HIGH; asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); if(OneWire_DQ) input_data |= 0x80; delay_time(OneWireDELAY_Read); } return(input_data); } /********************************************* * @fn OneWire_BusReset * @brief Reset all devices on the bus * @param None * @return None **********************************************/ void OneWire_BusReset(void) { OneWire_DQ = LOW; delay_time(100); OneWire_DQ = HIGH; } #if (HAL_ONEWIRE == TRUE) … #endif
  92. 92. DS18B20溫度感測器驅動程式 /*************************************************** Filename: hal_ds18b20.h Revised: $Date: 2013-11-05 $ Revision: $Revision: $ Description: This file contains the interface to the ds18b20 temperature sensor. ***************************************************/ #ifndef HAL_DS18B20_H #define HAL_DS18B20_H /******* INCLUDES *******/ #include "hal_board.h“ /******* CONSTANTS *******/ // DS18B20 ROM CMDs #define DS18B20_CMD_SEARCH_ROM 0xF0 #define DS18B20_CMD_READ_ROM 0x33 #define DS18B20_CMD_MATCH_ROM 0x55 #define DS18B20_CMD_SKIP_ROM 0xCC #define DS18B20_CMD_ALARM_SEARCH 0xEC // DS18B20 RAM CMDs #define DS18B20_CMD_CONVERT_TEMP 0x44 #define DS18B20_CMD_READ_SCRATCH 0xBE #define DS18B20_CMD_WRITE_SCRATCH 0x4E #define DS18B20_CMD_COPY_SCRATCH 0x48 #define DS18B20_CMD_RECALL_EPROM 0xB8 #define DS18B20_CMD_READ_PSUPPLY 0xB4 // DS18B20 Resolution #define DS18B20_RES_9BITS 0x1F #define DS18B20_RES_10BITS 0x3F #define DS18B20_RES_11BITS 0x5F #define DS18B20_RES_12BITS 0x7F #define DS18B20_CONV_TIME 752 /******* TYPEDEFS *******/ typedef struct __TEMPCONFIG__ { // 2's complement, +85C = 0101, 0101 = 0x55 uint8 Alarm_TH; // 2's complement, -10C = 1111, 0110 = 0xF6 uint8 Alarm_TL; uint8 Resolution; }TEMPCONFIG; typedef struct __SENSEDTEMP__ { bool Temp_Sign; uint8 Temp_Integer; uint8 Temp_Decimal; uint8 Resolution; char TempString[8]; }SENSEDTEMP; /******* FUNCTIONS - API *******/ extern void DS18B20_Init(void); extern void DS18B20_ReadTemp(SENSEDTEMP *ttemp); extern void DS18B20_Config(TEMPCONFIG *tconfig); #endif 92
  93. 93. 93 /*********************************************************************************** Filename: hal_ds18b20.c Revised: $Date: 2013-11-05 21:36 $ Revision: $Revision: $ Description: This file contains the interface to the ds18b20 temperature sensor. ***********************************************************************************/ /******* INCLUDES *******/ #include "hal_board_cfg.h" #include "hal_defs.h" #include "hal_types.h" #include "hal_drivers.h" #include "hal_ds18b20.h" #include "hal_onewire.h" /******* LOCAL FUNCTIONS *******/ void DS18B20_Wait_Conv(uint8 Resolution); /**************************************************** * @fn DS18B20_Init * @brief Initialize the DS18B20 on the bus * @param None * @return None ****************************************************/ void DS18B20_Init(void) { OneWire_DQ = HIGH; delay_time(1); OneWire_BusReset(); // Master Send Reset delay_time(50); } /********************************************************* * @fn DS18B20_Config * @brief DS18B20 configuration with temperature alarm * and resolution settings * @param *tconfig: pointer to the TEMPCONFIG struct * @return None ********************************************************/ void DS18B20_Config(TEMPCONFIG *tconfig) { OneWire_WriteByte(DS18B20_CMD_SKIP_ROM); OneWire_WriteByte(tconfig->Alarm_TH); OneWire_WriteByte(tconfig->Alarm_TL); OneWire_WriteByte(tconfig->Resolution); OneWire_ReadByte(); OneWire_ReadByte(); }
  94. 94. /***************************************************************************************** * @fn DS18B20_ReadTemp * @brief Read temperature from DS18B20 * @param *ttemp: pointer to SENSEDTEMP struct * @return None ****************************************************************************************/ void DS18B20_ReadTemp(SENSEDTEMP *ttemp) { uint8 temp_low_byte = 0; uint8 temp_high_byte = 0; uint8 temp_sign = 0; // send command: 1.Initialize, 2.ROM CMD, 3.RAM CMD DS18B20_Init(); OneWire_WriteByte(DS18B20_CMD_SKIP_ROM); OneWire_WriteByte(DS18B20_CMD_CONVERT_TEMP); DS18B20_Wait_Conv(ttemp->Resolution); DS18B20_Init(); OneWire_WriteByte(DS18B20_CMD_SKIP_ROM); OneWire_WriteByte(DS18B20_CMD_READ_SCRATCH); temp_low_byte = OneWire_ReadByte(); // temp low byte temp_high_byte = OneWire_ReadByte(); // temp high byte temp_sign = temp_high_byte & 0xF8; if(temp_sign) { ttemp->Temp_Sign = 1; // negative ttemp->Temp_Integer = ((LO_UINT8(temp_high_byte) << 4) | HI_UINT8(temp_low_byte)); ttemp->Temp_Integer = ~(ttemp->Temp_Integer) + 1; ttemp->Temp_Decimal = LO_UINT8(~(temp_low_byte & 0x0F)); }else{ ttemp->Temp_Sign = 0; // positive ttemp->Temp_Integer = ((LO_UINT8(temp_high_byte) << 4) | HI_UINT8(temp_low_byte)); ttemp->Temp_Decimal = LO_UINT8(temp_low_byte & 0x0F); } 94
  95. 95. 95 // String construction if(temp_sign) ttemp->TempString[0] = '-'; else ttemp->TempString[0] = ' '; if((ttemp->Temp_Integer)/100) { // hundred's digit ttemp->TempString[1] = ((ttemp->Temp_Integer)/100) + '0'; }else{ if(temp_sign) { ttemp->TempString[0] = ' '; ttemp->TempString[1] = '-'; }else{ ttemp->TempString[1] = ' '; } } if(((ttemp->Temp_Integer)%100)/10) { // ten's digit ttemp->TempString[2] = (((ttemp->Temp_Integer)%100)/10) + '0'; }else{ if(temp_sign) { ttemp->TempString[1] = ' '; ttemp->TempString[2] = '-'; }else{ ttemp->TempString[2] = ' '; } } ttemp->TempString[3] = ((ttemp->Temp_Integer)%10) + '0'; ttemp->TempString[4] = '.'; ttemp->TempString[5] = (ttemp->Temp_Decimal*625/1000) + '0'; ttemp->TempString[6] = 'C'; ttemp->TempString[7] = '0'; }
  96. 96. 96 /************************************************ * @fn DS18B20_Wait_Conv * @brief Waiting for temperature conversion * @param Resolution: The DS18B20 resolution * @return None ************************************************/ void DS18B20_Wait_Conv(uint8 Resolution) { switch(Resolution) { case DS18B20_RES_9BITS: delayms(DS18B20_CONV_TIME/8); break; case DS18B20_RES_10BITS: delayms(DS18B20_CONV_TIME/4); break; case DS18B20_RES_11BITS: delayms(DS18B20_CONV_TIME/4); delayms(DS18B20_CONV_TIME/4); break; case DS18B20_RES_12BITS: delayms(DS18B20_CONV_TIME/4); delayms(DS18B20_CONV_TIME/4); delayms(DS18B20_CONV_TIME/4); delayms(DS18B20_CONV_TIME/4); break; default: break; } } #if (HAL_DS18B20 == TRUE) … #endif
  97. 97. 1-Wire & DS18B20 驅動程式測試 97
  98. 98. 實習12 98  現在,請綜合驅動程式,寫一個應用程式,讓LCD不只 顯示出時間,也可顯示目前溫度。  步驟1: 加入1-wrie驅動程式 1. 加入hal_onewire.h / hal_onewire.c 2. 修改hal_board_cfg.h 3. 修改hal_drivers.c  步驟2: 加入DS18B20溫度感測器驅動程式 1. 加入hal_ds18b20.h / hal_ds18b20.c 2. 修改hal_board_cfg.h 3. 修改hal_drivers.c  步驟3: 撰寫應用程式
  99. 99. 含溫度顯示的電子時鐘應用程式 99 #include "MyAPP1.h" SYSTEMTIME currentTime; SENSEDTEMP currentTemp; TEMPCONFIG configTemp = {0x55, 0xF6, DS18B20_RES_11BITS}; void main() { HalDriverInit(); DS18B20_Config(&configTemp); OneWire_BusReset(); currentTemp.Resolution = configTemp.Resolution; while(1) { DS1302_ReadTime(&currentTime); LCD_DispStr(0, 0, currentTime.DateString); LCD_DispStr(0, 12, currentTime.WeekdayString); LCD_DispStr(1, 0, currentTime.TimeString); DS18B20_ReadTemp(&currentTemp); LCD_DispStr(1, 9, currentTemp.TempString); } }
  100. 100. Lab13 加入LED與Timer驅動程式 100
  101. 101. 實習13: 加入驅動程式並測試 101  練習1: 加入LED驅動程式並完成設定  練習2: 撰寫測試LED功能的應用程式  練習3: 加入Timer驅動程式並完成設定  練習4: 撰寫測試Timer功能的應用程式
  102. 102. 練習1: 加入LED驅動程式 (I) 102 /* ------------------------------------------------------------------------------------------------ * LED Configuration * ------------------------------------------------------------------------------------------------ */ #define HAL_NUM_LEDS 4 /* LED D0 */ #define LED1_BV BV(0) #define LED1_SBIT P1_bit.P1_0 #define LED1_POLARITY ACTIVE_LOW /* LED D5 */ #define LED2_BV BV(5) #define LED2_SBIT P1_bit.P1_5 #define LED2_POLARITY ACTIVE_LOW /* LED D6 */ #define LED3_BV BV(6) #define LED3_SBIT P1_bit.P1_6 #define LED3_POLARITY ACTIVE_LOW /* LED D7 */ #define LED4_BV BV(7) #define LED4_SBIT P1_bit.P1_7 #define LED4_POLARITY ACTIVE_LOW
  103. 103. 103 /* ------------------------------------------------------------------------------------------------ * Macros * ------------------------------------------------------------------------------------------------ /* ----------- LEDs ---------- */ #define HAL_TURN_OFF_LED1() st( LED1_SBIT = LED1_POLARITY (0); ) #define HAL_TURN_OFF_LED2() st( LED2_SBIT = LED2_POLARITY (0); ) #define HAL_TURN_OFF_LED3() st( LED3_SBIT = LED3_POLARITY (0); ) #define HAL_TURN_OFF_LED4() st( LED4_SBIT = LED4_POLARITY (0); ) #define HAL_TURN_ON_LED1() st( LED1_SBIT = LED1_POLARITY (1); ) #define HAL_TURN_ON_LED2() st( LED2_SBIT = LED2_POLARITY (1); ) #define HAL_TURN_ON_LED3() st( LED3_SBIT = LED3_POLARITY (1); ) #define HAL_TURN_ON_LED4() st( LED4_SBIT = LED4_POLARITY (1); ) #define HAL_TOGGLE_LED1() st( if (LED1_SBIT) { LED1_SBIT = 0; } else { LED1_SBIT = 1;} ) #define HAL_TOGGLE_LED2() st( if (LED2_SBIT) { LED2_SBIT = 0; } else { LED2_SBIT = 1;} ) #define HAL_TOGGLE_LED3() st( if (LED3_SBIT) { LED3_SBIT = 0; } else { LED3_SBIT = 1;} ) #define HAL_TOGGLE_LED4() st( if (LED4_SBIT) { LED4_SBIT = 0; } else { LED4_SBIT = 1;} ) #define HAL_STATE_LED1() (LED1_POLARITY (LED1_SBIT)) #define HAL_STATE_LED2() (LED2_POLARITY (LED2_SBIT)) #define HAL_STATE_LED3() (LED3_POLARITY (LED3_SBIT)) #define HAL_STATE_LED4() (LED4_POLARITY (LED4_SBIT)) /* ------------------------------------------------------------------------------------------------ * Driver Configuration * ------------------------------------------------------------------------------------------------ 略 /* Set to TRUE enable LED usage, FALSE disable it */ #ifndef HAL_LED #define HAL_LED TRUE #endif
  104. 104. 104 /************************************************************************ Filename: hal_led.h Revised: $Date: 2013-11-06 $ Revision: $Revision: $ Description: This file contains the interface to the LED Service. ************************************************************************/ #ifndef HAL_LED_H #define HAL_LED_H /***** INCLUDES *****/ #include "hal_board.h" /***** CONSTANTS *****/ #define HAL_LED_1 0x01 #define HAL_LED_2 0x02 #define HAL_LED_3 0x04 #define HAL_LED_4 0x08 #define HAL_LED_ALL (HAL_LED_1 | HAL_LED_2 | HAL_LED_3 | HAL_LED_4) /* Modes */ #define HAL_LED_MODE_OFF 0x00 #define HAL_LED_MODE_ON 0x01 #define HAL_LED_MODE_TOGGLE 0x02 /* Defaults */ #define HAL_LED_DEFAULT_MAX_LEDS 4 /* Initialize LED Service. */ extern void HalLedInit( void ); /* Set the LED ON/OFF */ extern uint8 HalLedSet( uint8 led, uint8 mode ); /* Put LEDs in sleep state - store current values */ extern void HalLedEnterSleep( void ); /* Retore LEDs from sleep state */ extern void HalLedExitSleep( void ); /* Return LED state */ extern uint8 HalLedGetState ( void ); #endif
  105. 105. 105 /************************************************************************* Filename: hal_led.c Revised: $Date: 2013-11-06 $ Revision: $Revision: 29281 $ Description: This file contains the interface to the HAL LED Service. **************************************************************************/ /***** INCLUDES *****/ #include "hal_mcu.h" #include "hal_defs.h" #include "hal_types.h" #include "hal_drivers.h" #include "hal_led.h" #include "hal_board.h" /***** GLOBAL VARIABLES *****/ // LED state at last set/clr update static uint8 HalLedState; #if HAL_LED == TRUE // LED state at last set/clr update static uint8 HalSleepLedState; #endif /***** LOCAL FUNCTION ******/ #if (HAL_LED == TRUE) void HalLedOnOff (uint8 leds, uint8 mode); #endif /* HAL_LED */ /***** FUNCTIONS - API ******/ /************************************************* * @fn HalLedInit * @brief Initialize LED Service * @param init - pointer to void that contains * the initialized value * @return None ************************************************/ void HalLedInit (void) { #if (HAL_LED == TRUE) /* Initialize all LEDs to OFF */ HalLedSet (HAL_LED_ALL, HAL_LED_MODE_OFF); #endif /* HAL_LED */ }
  106. 106. /********************************************************************* * @fn HalLedSet * @brief Tun ON/OFF given LEDs * @param led - bit mask value of leds to be turned ON/OFF/TOGGLE * mode - TOGGLE, ON, OFF * @return None ********************************************************************/ uint8 HalLedSet (uint8 leds, uint8 mode) { #if (HAL_LED == TRUE) uint8 i; if(mode == HAL_LED_MODE_TOGGLE) { for(i=0;i<HAL_LED_DEFAULT_MAX_LEDS;i++) { if (HalLedState & (1<<i)) HalLedOnOff(leds & (1<<i), HAL_LED_MODE_OFF); else HalLedOnOff(leds & (1<<i), HAL_LED_MODE_ON); } }else{ HalLedOnOff(leds, mode); } #endif return ( HalLedState ); } #if (HAL_LED == TRUE) /********************************************************* * @fn HalLedOnOff * @brief Turns specified LED ON or OFF * @param leds - LED bit mask * mode - LED_ON,LED_OFF, * @return none *********************************************************/ void HalLedOnOff (uint8 leds, uint8 mode) { if (leds & HAL_LED_1) { if (mode == HAL_LED_MODE_ON) HAL_TURN_ON_LED1(); else HAL_TURN_OFF_LED1(); } if (leds & HAL_LED_2) { if (mode == HAL_LED_MODE_ON) HAL_TURN_ON_LED2(); else HAL_TURN_OFF_LED2(); } 106
  107. 107. 107 if (leds & HAL_LED_3) { if (mode == HAL_LED_MODE_ON) HAL_TURN_ON_LED3(); else HAL_TURN_OFF_LED3(); } if (leds & HAL_LED_4) { if (mode == HAL_LED_MODE_ON) HAL_TURN_ON_LED4(); else HAL_TURN_OFF_LED4(); } /* Remember current state */ if (mode) HalLedState |= leds; else HalLedState &= (leds ^ 0xFF); } #endif /* HAL_LED */ /**************************************************** * @fn HalGetLedState * @brief Get LED state * @param none * @return led state ***************************************************/ uint8 HalLedGetState () { #if (HAL_LED == TRUE) return HalLedState; #else return 0; #endif }
  108. 108. 108 /*************************************************** * @fn HalLedEnterSleep * @brief Store current LEDs state before sleep * @param none * @return none ***************************************************/ void HalLedEnterSleep( void ) { #if (HAL_LED == TRUE) /* Save the state of each led */ HalSleepLedState = 0; HalSleepLedState |= HAL_STATE_LED1(); HalSleepLedState |= HAL_STATE_LED2() << 1; HalSleepLedState |= HAL_STATE_LED3() << 2; HalSleepLedState |= HAL_STATE_LED4() << 3; /* TURN OFF all LEDs to save power */ HalLedOnOff (HAL_LED_ALL, HAL_LED_MODE_OFF); #endif /* HAL_LED */ } /************************************************** * @fn HalLedExitSleep * @brief Restore current LEDs state after sleep * @param none * @return none *************************************************/ void HalLedExitSleep( void ) { #if (HAL_LED == TRUE) /* Load back the saved state */ HalLedOnOff(HalSleepLedState, HAL_LED_MODE_ON); #endif /* HAL_LED */ } void HalDriverInit (void) { 略 #if (defined HAL_LED) && (HAL_LED == TRUE) HalLedInit(); #endif 略 }
  109. 109. 練習2: 測試LED的應用程式 109  測試時先關閉DS1302 RTC與DS18B20測溫功能 #include "MyAPP1.h" void main() { uint8 read_keys; HalDriverInit(); uint8 sleep_flag = 0; while(1) { read_keys = 0x00; read_keys = HalKeyRead(); switch(read_keys) { case HAL_KEY_SW_1: if(!sleep_flag) { LCD_ClrLine(1); HalLedSet(HAL_LED_ALL, HAL_LED_MODE_ON); LCD_ClrLine(0); LCD_DispStr(0, 0, "LEDs ON"); } else { LCD_ClrLine(1); LCD_DispStr(1, 0, "LEDs are sleeping"); } break; case HAL_KEY_SW_2: if(!sleep_flag) { LCD_ClrLine(1); HalLedSet(HAL_LED_ALL, HAL_LED_MODE_OFF); LCD_ClrLine(0); LCD_DispStr(0, 0, "LEDs OFF"); }else{ LCD_ClrLine(1); LCD_DispStr(1, 0, "LEDs are sleeping"); } break;
  110. 110. 110 case HAL_KEY_SW_3: if(!sleep_flag) { LCD_ClrLine(1); HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE); HalLedSet(HAL_LED_2, HAL_LED_MODE_TOGGLE); HalLedSet(HAL_LED_3, HAL_LED_MODE_TOGGLE); HalLedSet(HAL_LED_4, HAL_LED_MODE_ON); LCD_ClrLine(0); LCD_DispStr(0, 0, "LEDs TOGGLE"); }else{ LCD_ClrLine(1); LCD_DispStr(1, 0, "LEDs are sleeping"); } break; case HAL_KEY_SW_4: if(!sleep_flag) { HalLedEnterSleep(); sleep_flag = 1; LCD_ClrLine(0); LCD_DispStr(0, 0, "LEDs: Sleeping"); } else { HalLedExitSleep(); LCD_ClrLine(1); LCD_ClrLine(0); LCD_DispStr(0, 0, "LEDs: Alive"); sleep_flag = 0; } break; } } }
  111. 111. 練習3: 加入Timer驅動程式並設定 111 /*********************************************************************** Filename: hal_timer.h Revised: $Date: 2013-11-1 $ Revision: $Revision: $ Description: This file contains the interface to the Timer Service. Just for demo, Timer2 is not implemented ***********************************************************************/ #ifndef HAL_TIMER_H #define HAL_TIMER_H /******** INCLUDES ********/ #include "hal_board.h" /******** CONSTANTS *******/ /* Timer ID definitions */ #define HAL_TIMER_0 0x00 // 8bit timer #define HAL_TIMER_1 0x01 // 16bit timer #define HAL_TIMER_INVALID 0x02 // Invalid timer #define HAL_TIMER_MAX 2 // Max number of timer /* Operation Modes for timer */ #define HAL_TIMER_MODE_13BITS 0x00 #define HAL_TIMER_MODE_16BITS 0x01 #define HAL_TIMER_MODE_8BITS_AUTO 0x02 #define HAL_TIMER_MODE_8BITS_SPLIT 0x03 #define HAL_TIMER_MODE_COUNT 0x04 #define HAL_TIMER_MODE_GATE 0x08 #define HAL_INT_ENABLE TRUE #define HAL_INT_DISABLE FALSE /* Error Code */ #define HAL_TIMER_OK 0x00 #define HAL_TIMER_NOT_OK 0x01 #define HAL_TIMER_PARAMS_ERROR 0x02 #define HAL_TIMER_NOT_CONFIGURED 0x03 #define HAL_TIMER_INVALID_ID 0x04 #define HAL_TIMER_INVALID_OP_MODE 0x05
  112. 112. 112 /******** TYPEDEFS ********/ typedef void (*halTimerCBack_t) (uint8 timerId); /******** FUNCTIONS - API ********/ /* Initialize Timer Service */ extern void HalTimerInit(void); /* Configure channel in different modes */ extern uint8 HalTimerConfig(uint8 timerId, uint8 opMode, bool intEnable, halTimerCBack_t cback ); /* Start a Timer */ extern uint8 HalTimerStart(uint8 timerId, uint16 timePerTick); /* Stop a Timer */ extern uint8 HalTimerStop(uint8 timerId); /* Enable and disable particular timer */ extern uint8 HalTimerInterruptEnable(uint8 timerId, bool enable); /************************************************************************************************* *************************************************************************************************/ #endif
  113. 113. 113 /*********************************************************************** Filename: hal_timer.c Revised: $Date: 2013-11-11 $ Revision: $Revision: $ Description: This file contains the interface to the Timer Service. Just for demo, Timer2 is not implemented ************************************************************************/ /******** INCLUDES ********/ #include "hal_mcu.h" #include "hal_defs.h" #include "hal_types.h" #include "hal_timer.h" #include "hal_led.h" /******** CONSTANTS ********/ // IE BV #define IE_T0_IntEn_Bit BV(1) #define IE_T1_IntEn_Bit BV(3) // IF BV@TCON #define TCON_T0_IntFlag_Bit BV(5) #define TCON_T1_IntFlag_Bit BV(7) // Timer Enable BV@TCON #define TCON_T0_START_BV BV(4) #define TCON_T1_START_BV BV(6) /* Prescale settings and Clock settings */ #define HAL_TIMER_PRESCALE_VAL 12 #define HAL_TIMER_12MHZ 12 /* ISR Vector names */ #define T0_VECTOR timer0 #define T1_VECTOR timer1 /* Opmode Mask */ #define OP_MODE_MASK 0x03 // for checking mode0, 1, 2, 3 /******** TYPEDEFS ********/ typedef struct { bool configured; bool intEnable; uint8 opMode; uint8 prescaleVal; uint8 clock; uint8 TH; uint8 TL; halTimerCBack_t callBackFunc; } halTimerSettings_t; /******** GLOBAL VARIABLES ********/ static halTimerSettings_t halTimerRecord[HAL_TIMER_MAX]; /******** FUNCTIONS – Local ********/ uint8 halTimerSetOpMode (uint8 timerId, uint8 opMode); uint8 halTimerSetCount (uint8 timerId, uint16 timePerTick); void halTimerSendCallBack (uint8 timerId); void halProcessTimer0 (void); void halProcessTimer1 (void); void halProcessTimer2 (void);
  114. 114. /*************************************************************************************************** * @fn HalTimerConfig * @brief Configure the Timer Serivce * @param timerId - Id of the timer, opMode - Operation mode, cBack - Pointer to callback function * @return Status of the configuration ***************************************************************************************************/ uint8 HalTimerConfig (uint8 timerId, uint8 opMode, bool intEnable, halTimerCBack_t cBack) { if (timerId < HAL_TIMER_MAX) { halTimerRecord[timerId].configured = TRUE; halTimerRecord[timerId].opMode = opMode; halTimerRecord[timerId].intEnable = intEnable; halTimerRecord[timerId].TH = 0; halTimerRecord[timerId].TL = 0; halTimerRecord[timerId].callBackFunc = cBack; } else { return HAL_TIMER_PARAMS_ERROR; } return HAL_TIMER_OK; } /******** FUNCTIONS – API ********/ /******************************************************************* * @fn HalTimerInit * @brief Initialize Timer Service * @param None * @return None *******************************************************************/ void HalTimerInit (void) { // disable all timer interrupts IE &= ~(IE_T0_IntEn_Bit|IE_T1_IntEn_Bit); /* Setup prescale value & clock for timer */ halTimerRecord[HAL_TIMER_0].clock = HAL_TIMER_12MHZ; halTimerRecord[HAL_TIMER_0].prescaleVal = HAL_TIMER_PRESCALE_VAL; halTimerRecord[HAL_TIMER_1].clock = HAL_TIMER_12MHZ; halTimerRecord[HAL_TIMER_1].prescaleVal = HAL_TIMER_PRESCALE_VAL; } 114
  115. 115. /************************************************************************************************* * @fn HalTimerStart * @brief Start the Timer Service * @param timerId - ID of the timer * timerPerTick - number of micro sec per tick, (ticks x prescale) / clock = usec/tick * @return Status - OK or Not OK *************************************************************************************************/ uint8 HalTimerStart (uint8 timerId, uint16 timePerTick) { if (halTimerRecord[timerId].configured) { halTimerSetOpMode (timerId, halTimerRecord[timerId].opMode); halTimerSetCount (timerId, timePerTick); HalTimerInterruptEnable(timerId, halTimerRecord[timerId].intEnable); if (timerId == HAL_TIMER_0) TCON |= TCON_T0_START_BV; if (timerId == HAL_TIMER_1) TCON |= TCON_T1_START_BV; } else { return HAL_TIMER_NOT_CONFIGURED; } return HAL_TIMER_OK; } /*************************************************** * @fn HalTimerStop * @brief Stop the Timer Service * @param timerId - ID of the timer * @return Status - OK or Not OK **************************************************/ uint8 HalTimerStop (uint8 timerId) { switch(timerId) { case HAL_TIMER_0: TCON &= ~(TCON_T0_START_BV); break; case HAL_TIMER_1: TCON &= ~(TCON_T1_START_BV); break; default: return HAL_TIMER_INVALID_ID; } return HAL_TIMER_OK; } 115
  116. 116. /*************************************************************************************************** * @fn halTimerSetCount * @brief * @param timerId - ID of the timer * timerPerTick - Number micro sec per ticks * @return Status - OK or Not OK ***************************************************************************************************/ uint8 halTimerSetCount (uint8 timerId, uint16 timePerTick) { uint16 count; uint8 high_byte, low_byte; /* Load count = ((sec/tick) x clock) / prescale */ //count = (uint16) (timePerTick*(halTimerRecord[timerId].prescaleVal)/halTimerRecord[timerId].clock); count = (uint16) (timePerTick); switch(halTimerRecord[timerId].opMode&OP_MODE_MASK) { case HAL_TIMER_MODE_13BITS: count = (8192 - count); high_byte = (uint8) (count >> 5); low_byte = (uint8) (count & 0x07); break; case HAL_TIMER_MODE_16BITS: count = (65536 - count); high_byte = (uint8) (count >> 8); low_byte = (uint8) (count & 0x0F); break; case HAL_TIMER_MODE_8BITS_AUTO: count = (256 - (uint8) count); high_byte = (uint8) count; low_byte = high_byte ; break; case HAL_TIMER_MODE_8BITS_SPLIT: count = (256 - (uint8) count); high_byte = (uint8) (count & 0x0F); low_byte = high_byte ; break; default: break; } halTimerRecord[timerId].TH = high_byte; halTimerRecord[timerId].TL = low_byte; switch(timerId) { case HAL_TIMER_0: TH0 = halTimerRecord[timerId].TH; TL0 = halTimerRecord[timerId].TL; break; case HAL_TIMER_1: TH1 = halTimerRecord[timerId].TH; TL1 = halTimerRecord[timerId].TL; break; default: return HAL_TIMER_INVALID_ID; } return HAL_TIMER_OK; } 116
  117. 117. /******************************************************* * @fn halTimerSetOpMode * @brief Setup operate modes * @param timerId - ID of the timer * opMode - operation mode of the timer * @return Status - OK or Not OK *******************************************************/ uint8 halTimerSetOpMode (uint8 timerId, uint8 opMode) { switch (timerId) { case HAL_TIMER_0: TMOD &= ~(0x0F); TMOD |= opMode; break; case HAL_TIMER_1: TMOD &= ~(0xF0); TMOD |= (opMode<<4); break; default: return HAL_TIMER_INVALID_ID; } return HAL_TIMER_OK; } /************************************************************ * @fn HalTimerInterruptEnable * @brief Setup interrupt enable * @param timerId - ID of the timer * enable - TRUE or FALSE * @return Status - OK or Not OK ************************************************************/ uint8 HalTimerInterruptEnable (uint8 timerId, bool enable) { switch(timerId) { case HAL_TIMER_0: if (halTimerRecord[timerId].intEnable) IE |= IE_T0_IntEn_Bit; else IE &= ~(IE_T0_IntEn_Bit); break; case HAL_TIMER_1: if (halTimerRecord[timerId].intEnable) IE |= IE_T1_IntEn_Bit; else IE &= ~(IE_T1_IntEn_Bit); break; default: return HAL_TIMER_INVALID_ID; } return HAL_TIMER_OK; } 117
  118. 118. 118 /****************************************************** * @fn halTimerSendCallBack * @brief Send Callback back to the caller * @param timerId - ID of the timer * @return None ******************************************************/ void halTimerSendCallBack (uint8 timerId) { if (halTimerRecord[timerId].callBackFunc) (halTimerRecord[timerId].callBackFunc) (timerId); } /******************************************* * @fn halProcessTimer0 * @brief Processes Timer 0 Events. ******************************************/ void halProcessTimer0 (void) { TCON &= ~(TCON_T0_IntFlag_Bit); TH0 = halTimerRecord[HAL_TIMER_0].TH; TL0 = halTimerRecord[HAL_TIMER_0].TL; halTimerSendCallBack(HAL_TIMER_0); } /****************************************** * @fn halProcessTimer1 * @brief Processes Timer 1 Events. *****************************************/ void halProcessTimer1 (void) { TCON &= ~(TCON_T1_IntFlag_Bit); TH1 = halTimerRecord[HAL_TIMER_1].TH; TL1 = halTimerRecord[HAL_TIMER_1].TL; halTimerSendCallBack(HAL_TIMER_1); } /****** INTERRUPT SERVICE ROUTINE ******/ /*************************************** * @fn halTimer0Isr * @brief Timer 0 ISR **************************************/ HAL_ISR_FUNCTION( halTimer0Isr, T0_VECTOR ) { halProcessTimer0(); } /*************************************** * @fn halTimer1Isr * @brief Timer 1 ISR **************************************/ HAL_ISR_FUNCTION( halTimer1Isr, T1_VECTOR ) { halProcessTimer1(); } /*************************************** ***************************************/ #if (HAL_TIMER == TRUE) … #endif
  119. 119. 練習4: 測試Timer的應用程式 119 #include "MyAPP1.h" uint8 count = 0; uint16 usec_per_tick; void Blink_LED(uint8 timerId); void main() { uint8 read_keys; HalDriverInit(); LCD_DispStr(0, 0, "Timer Demo"); HalTimerConfig(HAL_TIMER_0, HAL_TIMER_MODE_16BITS, HAL_INT_ENABLE, Blink_LED); HalTimerConfig(HAL_TIMER_1, HAL_TIMER_MODE_16BITS, HAL_INT_DISABLE, NULL); HAL_ENABLE_INTERRUPTS(); while(1) { read_keys = 0x00; read_keys = HalKeyRead(); switch(read_keys) { case HAL_KEY_SW_1: usec_per_tick = 1000; HalTimerStart(HAL_TIMER_0, usec_per_tick); LCD_ClrLine(0); LCD_DispStr(0, 0, "LED1 BLINK FAST"); break;
  120. 120. 120 case HAL_KEY_SW_2: usec_per_tick = 10000; HalTimerStart(HAL_TIMER_0, usec_per_tick); LCD_ClrLine(0); LCD_DispStr(0, 0, "LED1 BLINK SLOW"); break; case HAL_KEY_SW_3: HalTimerStop(HAL_TIMER_0); HalLedSet(HAL_LED_1, HAL_LED_MODE_OFF); LCD_ClrLine(0); LCD_DispStr(0, 0, "TIMER STOP"); break; case HAL_KEY_SW_4: HalLedSet(HAL_LED_ALL, HAL_LED_MODE_TOGGLE); LCD_ClrLine(0); LCD_DispStr(0, 0, "TIMER STOP"); break; default: break; } } } // This is the callback function when interrupt occur void Blink_LED(uint8 timerId) { if(count == 20) { count = 0; HalLedSet(HAL_LED_1, HAL_LED_MODE_TOGGLE); } count++; }
  121. 121. Lab14 建立新的應用程式 121
  122. 122. 建立新應用程式: 名稱為MyRTC 122
  123. 123. 複製一份MyAPP1來修改即可 123
  124. 124. 修改.ewp與.eww檔名與內容 124
  125. 125. 125
  126. 126. 全新而完整的應用程式 126
  127. 127. 總結 127  歷經三個PART,我們從最早從簡單的點亮LED實習來學 習嵌入式C語言的基本語法與技巧,同時觀察MCU的 header file內容以了解SFR與中斷向量的命名。  我們從main()函式中抽離出一切對硬體的操作,並且使 用函式將這類型的操作給包裝起來,稱之為驅動程式。  在一系列包含7段顯示器、LCD模組、中斷與計時器、 UART、AD/DA、ROM的讀寫、RTC與溫度感測器等實習, 我們循序漸進地學到「硬體驅動程式」與開發板SDK的 包裝,使得我們的開發專案能更有系統、簡潔而且有 效率地被重複使用。  這些經驗是如此的細微而且重要,還有很多韌體開發 及應用無法一一說完,但相信大家一定能藉著本系列 課程所學到基礎而能更容易地繼續往上蓋大樓。記住: 一法通,萬法通。

×