Chien-Jung Li
Nov. 2013
MCS-51 基礎實習
使用IAR Embedded Workbench (III)
Lab11: Real-Time Clock晶片
2
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可啟
動所有資料傳送。
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
DS1302之指令 – Command Byte
5
 Command Byte用於初始化每次的資料傳輸,bit-0必
定為input staring。
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.
RTC內部暫存器(儲存時間資訊)
7
Trickle Charger (涓流充電)
8
Timing Diagram
9
實習11
10
 目標:製作一個電子時鐘,將日期與時間顯示在LCD上。
這是我們第一次要同時控制兩個較複雜的裝置,它們
的驅動程式如果寫在一個.c檔,程式檔會變很龐大。現
在我們要開始學習如何管理程式碼,這是進入商用產
品開發的第一站。
 DS1302 RTC使用3-wire介面與MCU通訊
 LCD使用LCD1602A的訊號介面與MCU通訊
 練習1: 結構化你的程式碼
 練習2: 加入LCD的驅動程式
 練習3: 練習撰寫API手冊(以LCD驅動程式為例)
 練習4: 加入3-wire通訊介面與DS1302的驅動程式
 練習5: 完成電子時鐘
設計模式與驅動程式
11
 在開始談論如何結構化程式碼之前,我們先來討論
幾種跟硬體相關的嵌入式程式設計模式。
 所講到的觀念,以後會慢慢應用在我們的設計專案
當中(有些觀念其實你已經不知不覺接觸很久了)。
Adapter(或Wrapper)模式
12
 Adapter是十分傳統的設計模式,它將一個物件的介面
轉換成另一個用戶(高階模組)較易使用的介面。
 通常,adapter覆蓋在軟體API之上以蓋掉醜陋的介面。
閃爍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);
}
}
閃爍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);
}
}
閃爍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)
I/O處理程式碼
16
閃爍LED燈 – Facade模式
17
 LED的I/O子系統介面與內容,就是LED的驅動程式
 隱藏子系統的細節是良好設計中十分重要的一環,
呼叫端的程式不會依賴子系統的細節
Main
加上按鈕
18
設定中斷
19
 雖然為腳位設定中斷與設定輸入都是屬於初始化,但
這兩件事情通常會將實作分離,只需要在使用中斷的
程式碼中包含設定中斷的複雜度。
 三個中斷處理函式(有時會用巨集來做)
競賽情況(Race Condition)
 在工作間共享記憶體十分危險,必須十分小心。
20
避免競賽情況 – 使用mutex
21
 任何工作間共享的記憶體不論是讀取或寫入,都要在
程式中建立臨界區域(critical section),表示正在存取共
享資源(記憶體或設備),必須保護共享資源,同一時間
只能讓一個工作修改,稱為互斥(mutual exclusion),簡
寫為mutex。
 對於包含OS的系統,當兩個非中斷工作同時執行時,
能夠透過mutex表示兩個工作共享相同的資源,只需要
簡單地透過變數表示資源(或全域變數)可以供其他工作
使用就行了。
 當其中之一是中斷時,資源所有權的改變必須是單元
動作(atomic),單元動作是指無法被系統其他部分中斷
的動作。
結構化你的程式碼: Source Tree
22
 Source Tree:
擺放原始碼檔案的目錄結構,基本原則是一個目錄可以對應到系
統架構中的一個方塊。
 還記得我們在學C語言時,可以藉由撰寫Makefile來幫
助我們同時編譯多個原始碼嗎?
 在開發系統時,你必須告訴寫Makefile的工程師那些要
編譯的檔案放在哪裡,source tree結構規範就是在告訴
工程師這件事。
 寫Makefile這件事情有點麻煩,幸好我們有IDE開發環境
可以使用,我們只要將各種原始碼檔案分門別類放好,
再告訴IDE這些東西的Path在哪裡,剩下的就交給它吧!
常見目錄名稱的意思
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手冊等
練習1: 結構化你的程式碼
24
 在D槽新建一個目錄結構
 D:MySimpSystem
在IAR中New一個Worksapce
25
環境設定
26
New一個應用程式File
27
建立Groups
28
完成以下的Groups
29
先把幾個Header File歸入Group
30
D:MySimpSystemhaltargetJC51B
D:MySimpSystemhalinclude
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
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
/* 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
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
/*********************************************
*/
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
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
練習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
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
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
/*****************************************************************
* @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
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
/******** 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
將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
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
}
修改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
 先修改一下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
/* ----- 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
/**********************************************************************
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
/*********************************************
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
/******** 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
} 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
#else
void HalKeyInit(void)
{
}
void HalKeyConfig(bool interruptEnable)
{
}
uint8 HalKeyRead(void)
{
return 0;
}
#endif /* HAL_KEY */
/******************************************************************
******************************************************************/
加入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
在進行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);
}
}
}
}
顯現電路板設定組態檔的威力
 將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
練習3: 撰寫API手冊 (以LCD Driver為例)
56
57
58
59
60
61
為RTC準備什麼
62
 3-wire通訊介面的驅動程式
 DS1302的驅動程式
 寫完後將他們一一加入project的group
 修改hal_board_cfg.h
 寫出RTC的應用程式
練習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
加入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);
/*********************************************************
* @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
/*****************************************************************
* @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
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
測試驅動程式 (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
測試驅動程式 (II)
69
case HAL_KEY_SW_1:
TriWire_WriteByte(0x35);
break;
測試驅動程式 (III)
70
case HAL_KEY_SW_2:
TriWire_ReadByte();
break;
測試驅動程式 (IV)
71
case HAL_KEY_SW_3:
TriWire_Write(0xA2, 0xB4);
break;
測試驅動程式 (V)
72
case HAL_KEY_SW_4:
TriWire_Read(0x37);
break;
加入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
/*********************************************
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
}
}
/*************************************************************************************************
* @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
/*******************************************************************************
* @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);
}
/********************************************************************
* @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
/*****************************************************************************
* @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
修改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
修改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
}
練習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);
}
}
Lab12: DS18B20溫度感測器
82
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
內把溫度值轉換為數位值。
DS18B20架構說明
84
DS18B20的記憶體配置
85
與DS18B20進行通訊
86
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 。
Read/Write時序圖
88
使用注意事項
89
 DS1820與MCU使用串列通訊,因此對DS1820進行讀寫時必須嚴格
保證讀寫時序,否則將無法讀取測溫結果。
 實際應用中1-Wire bus上所掛DS1820數量並非任意多個,當數量超
過8個時就需要解決MCU的匯流排驅動問題。
 連接DS1820的匯流排電纜有長度限制,經驗中使用一般電線長度
超過50m時,讀取的測溫資料將發生錯誤。使用雙絞線帶遮罩電
纜時,正常通訊距離可達150m。
 DS1820測溫程式中,向DS1820發出溫度轉換命令後,程式總要等
待DS1820的返回訊號,一旦某個DS1820接觸不好或斷線,當程式
讀該DS1820時,將沒有返回訊號,程式進入閉迴路。這一點在進
行DS1820硬體連接和軟體設計時也要給予一定的重視。 測溫電纜
線建議採用遮罩4芯雙絞線,其中一對線接地線與訊號線,另一組
接VCC和地線,遮罩層在源端單點接地。
/*************************************************
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
/********************************************
* @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
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
/***********************************************************************************
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();
}
/*****************************************************************************************
* @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
// 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
/************************************************
* @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
1-Wire & DS18B20 驅動程式測試
97
實習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
#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);
}
}
Lab13 加入LED與Timer驅動程式
100
實習13: 加入驅動程式並測試
101
 練習1: 加入LED驅動程式並完成設定
 練習2: 撰寫測試LED功能的應用程式
 練習3: 加入Timer驅動程式並完成設定
 練習4: 撰寫測試Timer功能的應用程式
練習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
/* ------------------------------------------------------------------------------------------------
* 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
/************************************************************************
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
/*************************************************************************
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 */
}
/*********************************************************************
* @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
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
/***************************************************
* @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
略
}
練習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
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;
}
}
}
練習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
/******** 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
/***********************************************************************
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);
/***************************************************************************************************
* @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
/*************************************************************************************************
* @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
/***************************************************************************************************
* @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
/*******************************************************
* @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
/******************************************************
* @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
練習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
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++;
}
Lab14 建立新的應用程式
121
建立新應用程式: 名稱為MyRTC
122
複製一份MyAPP1來修改即可
123
修改.ewp與.eww檔名與內容
124
125
全新而完整的應用程式
126
總結
127
 歷經三個PART,我們從最早從簡單的點亮LED實習來學
習嵌入式C語言的基本語法與技巧,同時觀察MCU的
header file內容以了解SFR與中斷向量的命名。
 我們從main()函式中抽離出一切對硬體的操作,並且使
用函式將這類型的操作給包裝起來,稱之為驅動程式。
 在一系列包含7段顯示器、LCD模組、中斷與計時器、
UART、AD/DA、ROM的讀寫、RTC與溫度感測器等實習,
我們循序漸進地學到「硬體驅動程式」與開發板SDK的
包裝,使得我們的開發專案能更有系統、簡潔而且有
效率地被重複使用。
 這些經驗是如此的細微而且重要,還有很多韌體開發
及應用無法一一說完,但相信大家一定能藉著本系列
課程所學到基礎而能更容易地繼續往上蓋大樓。記住:
一法通,萬法通。

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

  • 1.
    Chien-Jung Li Nov. 2013 MCS-51基礎實習 使用IAR Embedded Workbench (III)
  • 2.
  • 3.
    DS1302 RTC介紹 3  DS1302是美國DALLAS公司生產的即時時鐘電路(Real- timeclock, 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.
    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.
    DS1302之指令 – CommandByte 5  Command Byte用於初始化每次的資料傳輸,bit-0必 定為input staring。
  • 6.
    3-Wire通訊介面的讀寫 6 Burst mode: commandbyte bit1~5 = 11111’b = 31(decimal) Reads or writes in burst mode start with bit 0 of address 0.
  • 7.
  • 8.
  • 9.
  • 10.
    實習11 10  目標:製作一個電子時鐘,將日期與時間顯示在LCD上。 這是我們第一次要同時控制兩個較複雜的裝置,它們 的驅動程式如果寫在一個.c檔,程式檔會變很龐大。現 在我們要開始學習如何管理程式碼,這是進入商用產 品開發的第一站。  DS1302RTC使用3-wire介面與MCU通訊  LCD使用LCD1602A的訊號介面與MCU通訊  練習1: 結構化你的程式碼  練習2: 加入LCD的驅動程式  練習3: 練習撰寫API手冊(以LCD驅動程式為例)  練習4: 加入3-wire通訊介面與DS1302的驅動程式  練習5: 完成電子時鐘
  • 11.
  • 12.
  • 13.
    閃爍LED燈 – 最簡單的寫法 13 #include<ioAT89C52.h> typedefunsigned 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.
    閃爍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.
    閃爍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.
  • 17.
    閃爍LED燈 – Facade模式 17 LED的I/O子系統介面與內容,就是LED的驅動程式  隱藏子系統的細節是良好設計中十分重要的一環, 呼叫端的程式不會依賴子系統的細節 Main
  • 18.
  • 19.
  • 20.
  • 21.
    避免競賽情況 – 使用mutex 21 任何工作間共享的記憶體不論是讀取或寫入,都要在 程式中建立臨界區域(critical section),表示正在存取共 享資源(記憶體或設備),必須保護共享資源,同一時間 只能讓一個工作修改,稱為互斥(mutual exclusion),簡 寫為mutex。  對於包含OS的系統,當兩個非中斷工作同時執行時, 能夠透過mutex表示兩個工作共享相同的資源,只需要 簡單地透過變數表示資源(或全域變數)可以供其他工作 使用就行了。  當其中之一是中斷時,資源所有權的改變必須是單元 動作(atomic),單元動作是指無法被系統其他部分中斷 的動作。
  • 22.
    結構化你的程式碼: Source Tree 22 Source Tree: 擺放原始碼檔案的目錄結構,基本原則是一個目錄可以對應到系 統架構中的一個方塊。  還記得我們在學C語言時,可以藉由撰寫Makefile來幫 助我們同時編譯多個原始碼嗎?  在開發系統時,你必須告訴寫Makefile的工程師那些要 編譯的檔案放在哪裡,source tree結構規範就是在告訴 工程師這件事。  寫Makefile這件事情有點麻煩,幸好我們有IDE開發環境 可以使用,我們只要將各種原始碼檔案分門別類放好, 再告訴IDE這些東西的Path在哪裡,剩下的就交給它吧!
  • 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.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 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.
    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 /* 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.
    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.
    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.
    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.
    練習2: 加入LCD的驅動程式 #include<ioAT89C52.h> #define BTN1P3_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 static void LCD_CursorSet(uint8row, 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 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 /***************************************************************** * @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 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 /******** 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.
    將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 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.
    修改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  先修改一下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 /* ----- 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 /********************************************************************** 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 /********************************************* 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.
    /******** 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.
    } 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 #else void HalKeyInit(void) { } void HalKeyConfig(boolinterruptEnable) { } uint8 HalKeyRead(void) { return 0; } #endif /* HAL_KEY */ /****************************************************************** ******************************************************************/
  • 53.
  • 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.
    顯現電路板設定組態檔的威力  將driver與硬體I/O相關的設定移到hal_borad_cfg.h #define LCD_RWP1_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.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
    為RTC準備什麼 62  3-wire通訊介面的驅動程式  DS1302的驅動程式 寫完後將他們一一加入project的group  修改hal_board_cfg.h  寫出RTC的應用程式
  • 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.
    加入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.
    /********************************************************* * @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 /***************************************************************** * @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.
    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.
    測試驅動程式 (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.
  • 70.
  • 71.
  • 72.
  • 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 /********************************************* 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.
    /************************************************************************************************* * @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 /******************************************************************************* * @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.
    /******************************************************************** * @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 /***************************************************************************** * @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.
    修改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.
    修改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.
    練習5: 寫一支電子時鐘應用程式 81 #include "MyAPP1.h" SYSTEMTIMEcurrentTime; /* 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.
  • 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.
  • 85.
  • 86.
  • 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.
  • 89.
    使用注意事項 89  DS1820與MCU使用串列通訊,因此對DS1820進行讀寫時必須嚴格 保證讀寫時序,否則將無法讀取測溫結果。  實際應用中1-Wirebus上所掛DS1820數量並非任意多個,當數量超 過8個時就需要解決MCU的匯流排驅動問題。  連接DS1820的匯流排電纜有長度限制,經驗中使用一般電線長度 超過50m時,讀取的測溫資料將發生錯誤。使用雙絞線帶遮罩電 纜時,正常通訊距離可達150m。  DS1820測溫程式中,向DS1820發出溫度轉換命令後,程式總要等 待DS1820的返回訊號,一旦某個DS1820接觸不好或斷線,當程式 讀該DS1820時,將沒有返回訊號,程式進入閉迴路。這一點在進 行DS1820硬體連接和軟體設計時也要給予一定的重視。 測溫電纜 線建議採用遮罩4芯雙絞線,其中一對線接地線與訊號線,另一組 接VCC和地線,遮罩層在源端單點接地。
  • 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 /******************************************** * @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.
    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 /*********************************************************************************** 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.
    /***************************************************************************************** * @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 // 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 /************************************************ * @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.
    1-Wire & DS18B20驅動程式測試 97
  • 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 #include "MyAPP1.h" SYSTEMTIME currentTime; SENSEDTEMPcurrentTemp; 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.
  • 101.
    實習13: 加入驅動程式並測試 101  練習1:加入LED驅動程式並完成設定  練習2: 撰寫測試LED功能的應用程式  練習3: 加入Timer驅動程式並完成設定  練習4: 撰寫測試Timer功能的應用程式
  • 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 /* ------------------------------------------------------------------------------------------------ * 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 /************************************************************************ 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 /************************************************************************* 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.
    /********************************************************************* * @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 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 /*************************************************** * @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.
    練習2: 測試LED的應用程式 109  測試時先關閉DS1302RTC與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 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.
    練習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 /******** TYPEDEFS ********/ typedefvoid (*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 /*********************************************************************** 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.
    /*************************************************************************************************** * @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.
    /************************************************************************************************* * @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.
    /*************************************************************************************************** * @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.
    /******************************************************* * @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 /****************************************************** * @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.
    練習4: 測試Timer的應用程式 119 #include "MyAPP1.h" uint8count = 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 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.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
    總結 127  歷經三個PART,我們從最早從簡單的點亮LED實習來學 習嵌入式C語言的基本語法與技巧,同時觀察MCU的 header file內容以了解SFR與中斷向量的命名。 我們從main()函式中抽離出一切對硬體的操作,並且使 用函式將這類型的操作給包裝起來,稱之為驅動程式。  在一系列包含7段顯示器、LCD模組、中斷與計時器、 UART、AD/DA、ROM的讀寫、RTC與溫度感測器等實習, 我們循序漸進地學到「硬體驅動程式」與開發板SDK的 包裝,使得我們的開發專案能更有系統、簡潔而且有 效率地被重複使用。  這些經驗是如此的細微而且重要,還有很多韌體開發 及應用無法一一說完,但相信大家一定能藉著本系列 課程所學到基礎而能更容易地繼續往上蓋大樓。記住: 一法通,萬法通。