SlideShare a Scribd company logo
1 of 99
Download to read offline
Chien-Jung Li
Sept. 2013
MCS-51 基礎實習
使用IAR Embedded Workbench (I)
開發板認識
2
燒錄程式的安裝 (I)
1) PC安裝PL2303_Prolific_DriverInstaller_v1210驅動程式。
2) 將燒錄程式「STC-ISP-V488_燒錄程式_免安裝」解壓
縮 到 D 槽 ( 或 C 槽 也 可 ) 。 解 完 後 將 目 錄 裡 的
STC_ISP_V488.exe建立桌面捷徑。
3
燒錄程式的安裝 (II)
3) 安裝AppLocale: papplc.msi (要先改相容性)。裝完後,
再點擊「簡體中文執行_右鍵選單註冊.reg」。
4
燒錄程式的安裝 (III)
4) 點選STC_ISP_488程式,從右鍵選單中選擇「以簡體中
文執行」。(在64位元win7無法開啟程式,請見下頁)
5
64位元win7系統使用STC-ISP程式
 在64位元系統要執行ISP時,可能出現以下錯誤:
 解法:
1) 到 D:STC-ISP-V488 目 錄 下 將 MSSTDFMT.dll 、 comdlg32.ocx 、
mscomctl.ocx 、 mscomm32.ocx 這 四 支 檔 案 拷 貝 至
C:WindowsSysWOW64目錄下。(若檔案已存在,不要覆蓋)
2) 在C:WindowsSysWOW64目錄下找到cmd.exe,以管理員執行。
接著於終端輸入
regsvr32 mscomm32.ocx
regsvr32 comdlg32.ocx
註 冊 完 再 執 行 ISP 程 式 試 試 看 , 如 果 還 不 能 執 行 , 再 註 冊
MSSTDFMT.dll與mscomctl.ocx這兩支檔案。
6
燒錄程式的安裝 (IV)
5) 接上USB (在裝置管理員看一下連接埠號碼)
6) 執行ISP燒錄程式
7) 選擇一支測試映像檔燒錄看看(作法見下頁)
7
燒錄映像檔
8
安裝8051嵌入式開發環境
 目前大多數的MCS-51開發都以Kiel C這套軟體為主
 為了能跟以後要開發的SoC晶片銜接,我們改用IAR
這套IDE來進行開發。
9
使用IAR – 開啟新專案
10
環境設定 (I) – 選擇裝置
11
環境設定 (II) – 設定Linker
12
環境設定 (III) – 其它 (可不用設定)
13
第一支程式 (I)
14
第一支程式 (II)
#include<ioAT89C52.h>
void main()
{
unsigned int a = 0;
while(1)
{
a = 50000;
while(a--);
a = 50000;
while(a--);
a = 50000;
P1 &= ~(1 << 2);
while(a--);
a = 50000;
while(a--);
a = 50000;
P1 &= ~(1 << 0);
P1 &= ~(1 << 5);
P1 &= ~(1 << 6);
while(a--);
P1 |= (1 << 6);
}
}
15
第一支程式 (III)
16
認識MCU的Header File
MCS-51 AT89C52介紹
 Compatible with MCS-51™ Products
 8K Bytes Flash Memory
 Fully Static Operation: 0 Hz to 24 MHz
 256 x 8-bit Internal RAM
 32 Programmable I/O Lines
 Three 16-bit Timer/Counters
 8 Interrupt Sources
 Programmable Serial Channel
 Low-power Idle and Power-down Modes
18
特殊暫存器(SFR) – 透過它們控制MCU
19
Header File
/***************************************************************************
* - ioAT89C52.h -
*
* Special header for the Atmel AT89C52 Microcontroller.
***************************************************************************/
#ifndef IOAT89C52_H
#define IOAT89C52_H
#define __AT89C52__
#ifdef __IAR_SYSTEMS_ICC__
#ifndef _SYSTEM_BUILD
#pragma system_include
#endif
#pragma language=extended
/*-------------------------------------------------------------------------
* Power and clock control registers
*-------------------------------------------------------------------------*/
__sfr __no_init volatile union
{
unsigned char PCON; /* Power Control */
struct /* Power Control */
{
unsigned char IDL : 1;
unsigned char PD : 1;
unsigned char GF0 : 1;
unsigned char GF1 : 1;
unsigned char : 1;
unsigned char : 1;
unsigned char : 1;
unsigned char SMOD : 1;
} PCON_bit;
} @ 0x87;
20
__sfr __no_init volatile unsigned char TH0 @ 0x8C; /* Timer/Counter 0 High Byte */
__sfr __no_init volatile union
{
unsigned char TCON; /* Timer/Counter Control */
struct /* Timer/Counter Control */
{
unsigned char IT0 : 1;
unsigned char IE0 : 1;
unsigned char IT1 : 1;
unsigned char IE1 : 1;
unsigned char TR0 : 1;
unsigned char TF0 : 1;
unsigned char TR1 : 1;
unsigned char TF1 : 1;
} TCON_bit;
} @ 0x88;
__sfr __no_init volatile unsigned char TH2 @ 0xCD; /* Timer/Counter 2 High Byte */
__sfr __no_init volatile unsigned char TH1 @ 0x8D; /* Timer/Counter 1 High Byte */
__sfr __no_init volatile union
{
unsigned char TMOD; /* Timer/Counter Mode Control */
struct /* Timer/Counter Mode Control */
{
unsigned char M00 : 1;
unsigned char M10 : 1;
unsigned char C_T0 : 1;
unsigned char GATE0 : 1;
unsigned char M01 : 1;
unsigned char M11 : 1;
unsigned char C_T1 : 1;
unsigned char GATE1 : 1;
} TMOD_bit;
} @ 0x89; 21
/*-------------------------------------------------------------------------
* I/O port registers
*-------------------------------------------------------------------------*/
__sfr __no_init volatile union
{
unsigned char P1; /* Port 1 */
struct /* Port 1 */
{
unsigned char P1_0 : 1;
unsigned char P1_1 : 1;
unsigned char P1_2 : 1;
unsigned char P1_3 : 1;
unsigned char P1_4 : 1;
unsigned char P1_5 : 1;
unsigned char P1_6 : 1;
unsigned char P1_7 : 1;
} P1_bit;
} @ 0x90;
__sfr __no_init volatile union
{
unsigned char P0; /* Port 0 */
struct /* Port 0 */
{
unsigned char P0_0 : 1;
unsigned char P0_1 : 1;
unsigned char P0_2 : 1;
unsigned char P0_3 : 1;
unsigned char P0_4 : 1;
unsigned char P0_5 : 1;
unsigned char P0_6 : 1;
unsigned char P0_7 : 1;
} P0_bit;
} @ 0x80;
/*---------------------------------------------
* Interrupt system registers
*---------------------------------------------*/
__sfr __no_init volatile union
{
unsigned char IE; /* Interrupt Enable Control */
struct /* Interrupt Enable Control */
{
unsigned char EX0 : 1;
unsigned char ET0 : 1;
unsigned char EX1 : 1;
unsigned char ET1 : 1;
unsigned char ES : 1;
unsigned char ET2 : 1;
unsigned char : 1;
unsigned char EA : 1;
} IE_bit;
} @ 0xA8;
22
小程式
#include <ioAT89C52.h>
void main(){ // 主程式一定叫main()
while(1){ // 嵌入式系統會持續run下去
P1_bit.P1_0 = 0; // 設定port1的第0埠
// 假設該腳是Active Low
}
}
23
Data Types (IAR)
24
自己定義資料型別關鍵字
25
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;
Lab1:以點亮LED學習輸出
範例實習1
 請打開lab1_Output_LED
 練習1: 學習依照header filer指定SFR來使用輸出
 練習2: 使用#define來訂別名
 練習3, 4: 使用「位元組」操作LED
 練習5: 學習移位運算子
 練習6: 使用巨集
 練習7, 8: 延遲為ms等級的函數
27
練習1:SFR的使用
28
/*************************************************************
Filename: exercise1-01.c
Description: 學習如何依照header filer對I/O SFR的定義來使用輸出
**************************************************************/
#include<ioAT89C52.h> // 這個header定義了SFR的"名稱"與記憶體位址的對應
// 以後我們就可以直接對SFR的"名稱變數"操作,而不用對"記憶體位址"的內容作操作
void main()
{
while(1)
{
P1_bit.P1_0 = 0;// AT89C52開發板輸出
// 是active low,
// 輸出為0時, LED點亮
}
}
// 開發板上的八顆LED {D0, D1, ..., D7},
// 分別對應到 {P1_0, P1_1, ..., P1_7}
// 練習1: 點亮D1
// 練習2: 點亮D0, D1, D7
__sfr __no_init volatile union
{
unsigned char P1; /* Port 1 */
struct /* Port 1 */
{
unsigned char P1_0 : 1;
unsigned char P1_1 : 1;
unsigned char P1_2 : 1;
unsigned char P1_3 : 1;
unsigned char P1_4 : 1;
unsigned char P1_5 : 1;
unsigned char P1_6 : 1;
unsigned char P1_7 : 1;
} P1_bit;
} @ 0x90;
練習2:預編譯語法#define的使用
29
/**********************************************************************
Filename: exercise1-02.c
Description: 使用#define定義port的"別名",用"別名"有時候看起來會更容易理解
***********************************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
#define LED1 P1_bit.P1_1
#define LED2 P1_bit.P1_2
#define LED3 P1_bit.P1_3
#define LED4 P1_bit.P1_4
#define LED5 P1_bit.P1_5
#define LED6 P1_bit.P1_6
#define LED7 P1_bit.P1_7
void main()
{
while(1)
{
LED0 = 0;
}
}
// 練習1: 使用別名點亮D1
// 練習2: 使用別名點亮D0, D1, D7
#define LED0 P1_bit.P1_0
#define LED1 P1_bit.P1_1
練習3:使用位元組設定操作LED
30
/************************************************************
Filename: exercise1-03.c
Description: 對位元組"P1"操作來點亮LED0,而不是用單一位元的操作
*************************************************************/
#include<ioAT89C52.h>
void main()
{
while(1)
{
P1 = 0xFE; // 1111,1110
}
}
// 開發板上的八顆LED {D0, D1, ..., D7},
// 分別對應到 {P1_0, P1_1, ..., P1_7}
//
// 練習1: 使用 #define 將P1的別名設定為 LED,
// 然後對"LED"別名進行操作同時點亮
// LED0, LED2, LED4
P1_bit.P1_0 = 0; // 位元操作
P1 = 0xFE; // 位元組操作
練習4:使用位元組設定操作LED
31
/*******************************************************************************
Filename: exercise1-04.c
Description: 操作位元組"P1"點亮D2,延時一段時間後,"再"點亮D0, D5, D6 (D2不可熄滅)
*******************************************************************************/
#include<ioAT89C52.h>
void main()
{
unsigned int a = 0; // 在IAR/Kiel中, int的型別是16位元, unsigned int範圍為0~65535
while(1)
{
a = 50000;
P1 = 0xFB; // 1111,1011 點亮D2
while(a--);
a = 50000;
P1 = 0x9A; // 1001,1010 點亮D0, D5, D6, 但D2也維持點亮
while(a--);
while(1); // 將此行註解掉, LED會開始閃爍
// while(1)不可亂用, 因程式會在此卡死, 這裡只是demo
}
}
// 練習1: 對"位元組"使用"位元操作"運算, 將第16行更改為
// P1 &= ~(0x61); // 0110,0001
// 想想看, 這是甚麼原理?
// 練習2: 點亮D0, D2, D5, D6之後,延遲一段時間,熄滅D6。將18行改為
// a = 50000;
// P1 |= 0x40; // 0100,0000
// while(a--);
// 想想看, 這是甚麼原理?
// 當我們要對"位元組"內的某個、或某幾個bits做設定,但又不影響其他bits原有的狀態時,
// 位元操作運算 &= 與 |= 是非常實用而且常見的運算手法喔!
P1 &= ~(0x61) // 位元操作, 設為0
P1 |= 0x40 // 位元操作, 設為1
/****************************************************************************************
Filename: exercise1-05.c
Description: 學會使用移位操作,設定"P1"點亮D2,延時一段時間後,"再"點亮D0, D5, D6 (D2不可熄滅)
再延遲一段時間後,關閉熄滅D6
*****************************************************************************************/
#include<ioAT89C52.h>
void main()
{
unsigned int a = 0;
while(1)
{
a = 50000;
while(a--);
a = 50000;
while(a--);
a = 50000;
P1 &= ~(1 << 2); // 將1左移2位再取~ 得到 1111,1011 點亮D2
while(a--);
a = 50000;
while(a--);
a = 50000;
P1 &= ~(1 << 0); // 0000,0001 -> 1111,1110 點亮D0
P1 &= ~(1 << 5); // 0010,0000 -> 1101,1111 點亮D5
P1 &= ~(1 << 6); // 0100,0000 -> 1011,1111 點亮D6
while(a--);
P1 |= (1 << 6); // 0100,0000 熄滅D6
}
}
練習5:學習移位運算子
32
P1 &= ~(1<<2); // 位元操作, 設為0
P1 |= (1<<2); // 位元操作, 設為1
/**************************************************************************************************
Filename: exercise1-06.c
Description: 學會使用巨集(macro)以簡化程式碼的寫法, 重新改寫exercise1-05.c
**************************************************************************************************/
#include<ioAT89C52.h>
#define BV(n) (1 << (n)) // 這是向左移位操作的macro
void main()
{
unsigned int a = 0;
while(1)
{
a = 50000;
while(a--);
a = 50000;
while(a--);
a = 50000;
P1 &= ~BV(2); // 將1左移2位再取~ 得到 1111,1011 點亮D2
while(a--);
a = 50000;
while(a--);
a = 50000;
P1 &= ~BV(0); // 0000,0001 -> 1111,1110 點亮D0
P1 &= ~BV(5); // 0010,0000 -> 1101,1111 點亮D5
P1 &= ~BV(6); // 0100,0000 -> 1011,1111 點亮D6
while(a--);
P1 |= BV(6); // 0100,0000 熄滅D6
}
}
練習6:使用巨集(Macro)
33
#define BV(n) (1 << (n))
/*************************************************************************
Filename: exercise1-07.c
Description: 將延時放的更長
***************************************************************************/
#include<ioAT89C52.h>
#define BV(n) (1 << (n)) // 這是向左移位操作的macro
typedef signed char int8; // 以後8位元的有號數就可以用int8做宣告
typedef unsigned char uint8; // 以後8位元的無號數就可以用uint8做宣告
void delay(uint8); // delay函數的宣告
void main()
{
while(1)
{
P1 &= ~BV(2); // 將1左移2位再取~ 得到 1111,1011 點亮D2
delay(255);
delay(255);
P1 &= ~BV(0); // 0000,0001 -> 1111,1110 點亮D0
P1 &= ~BV(5); // 0010,0000 -> 1101,1111 點亮D5
P1 &= ~BV(6); // 0100,0000 -> 1011,1111 點亮D6
delay(255);
P1 |= BV(6); // 0100,0000 熄滅D6
delay(150);
}
}
void delay(uint8 d) // delay函數的定義, 也就是這個函數要執行的動作
{
uint8 x,y;
for(x=d;x>0;x--)
for(y=255;y>0;y--);
}
// 使用雙for迴圈來延長時間, 最高可延長 256*256 = 65536 (65535遞減至0)
// 在這個練習裡, 你也學到函數的宣告與定義
// 練習: 試著改變延時的長度
練習7:延時函式
34
unsigned int a = 0;
a = 50000;
while(a--);
練習8:毫秒(ms)等級的延時函式
35
/************************************************************************
Filename: exercise1-08.c
Description: 1ms延遲函數, 將延時放的更長
*************************************************************************/
#include<ioAT89C52.h>
#define BV(n) (1 << (n)) // 這是向左移位操作的macro
typedef signed char int8; // 以後8位元的有號數就可以用int8做宣告
typedef unsigned char uint8; // 以後8位元的無號數就可以用uint8做宣告
void delayms(uint8); // delay函數的宣告
void main()
{
while(1)
{
P1 &= ~BV(0); // 點亮D0
delayms(255);
delayms(245);
P1 |= BV(0); // 熄滅D0
delayms(255);
delayms(245);
}
}
void delayms(uint8 time)
{
uint8 n;
while(time>0)
{
n = 162;
while(n>0) n--;
time --;
}
}
小錦囊 (I)
36
#define LED0 P1_bit.P1_0
P1 &= ~(1 << 0); // 0000,0001 -> 1111,1110
P1 |= (1 << 6); // 0100,0000
#define BV(n) (1 << (n)) // 這是向左移位操作的macro
P1 &= ~BV(5); // 0010,0000 -> 1101,1111
P1 |= BV(6); // 0100,0000
typedef signed char int8;
typedef unsigned char uint8;
小錦囊 (II)
37
void delayms(uint8 time)
{
uint8 n;
while(time>0)
{
n = 162;
while(n>0) n--;
time --;
}
}
驅動程式的概念
38
 把「對硬體的操作」包裝成函式,即為該硬體裝置
的驅動程式(這是最簡單的說法)。
 一般而言,嵌入式系統驅動程式的介面都是以模仿
UNIX系統呼叫設備的API為基礎,介面十分直接:
open():開啟裝置,嵌入式系統有時也用init()取代
close():關閉裝置
read():自裝置讀取資料
write():傳送資料到裝置
ioctl():I/O的控制以及處理介面其他未涵蓋的部分
LED0的驅動程式(I)
39
 為方便說明,我們僅以單一顆LED0的閃爍為例:
/*********************************************************************
Filename: exercise1-09.c
Description: 以函式包裝對LED0的操作(最簡單的驅動程式)
*********************************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
typedef unsigned char uint8;
/* Declare Function Prototype */
void drv_LED0_Init(void);
void drv_LED0_Toggle(void);
void delayms(uint8);
void main(void)
{
drv_LED0_Init();
while(1)
{
drv_LED0_Toggle(); // Change LED state
delayms(250); // Delay for 250 ms
delayms(250); // Delay for 250 ms, 1 Hz Flash = 0.5s On + 0.5s OFF
}
}
LED0的驅動程式(II)
40
/***********************************************************************
* @fn drv_LED0_Init
* @brief Initialize LED0 State
* @param None
* @return None
**********************************************************************/
void drv_LED0_Init(void)
{
LED0 = 1; // 初始時LED0熄滅
}
/***********************************************************************
* @fn drv_LED0_Toggle
* @brief Changes LED0 State
* @param None
* @return None
**********************************************************************/
void drv_LED0_Toggle(void)
{
// Change the LED from OFF to ON (or vice versa)
LED0 = ~LED0;
}
LED0的驅動程式(III)
41
/**********************************************************************
* @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 drv_LED0_Off
* @brief Turn Off LED0
* @param None
* @return None
************************************/
void drv_LED0_Off(void)
{
LED0 = 1;
}
用On/Off函式並使用全域變數(I)
42
 將exercise1-09.c另存為exercise1-10.c,並加入:
uint8 gLED0_state; // 'g' notice us it's a global var.
void drv_LED0_Init(void);
void drv_LED0_On(void);
void drv_LED0_Off(void);
void drv_LED0_Toggle(void);
void delayms(uint8);
/************************************
* @fn drv_LED0_On
* @brief Turn On LED0
* @param None
* @return None
************************************/
void drv_LED0_On(void)
{
LED0 = 0;
}
用On/Off函式並使用全域變數(II)
43
/***************************************************************
* @fn drv_LED0_Toggle
* @brief Changes LED0 State
* @param None
* @return None
**************************************************************/
void drv_LED0_Toggle(void)
{
// Change the LED from OFF to ON (or vice versa)
if (gLED0_state == 1)
{
gLED0_state = 0;
drv_LED0_Off();
}
else
{
gLED0_state = 1;
drv_LED0_On();
}
}
Lab2:按壓按鍵點亮LED學習輸入
鍵盤分類
45
範例實習2
 請打開lab2_Input_Button
 練習1: 使用輸入 (持續按下時LED點亮)
 練習2: 使用輸入 (按一下button即可開關LED)
 練習3: 簡易軟體debounce
 練習4: 以函式包裝檢測按鍵是否被按下的功能
46
練習1:持續按下時LED點亮
47
/**********************************************************************************
Filename: exercise2-01.c
Description: 使用button (這個程式還未使用中斷)
***********************************************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
#define BTN1 P3_bit.P3_2
void main()
{
BTN1 = 1; // I/O要當輸入時,要先寫入1
while(1)
{
if (BTN1 == 0){
LED0 = 0;
}else{
LED0 = 1;
}
}
}
// 程式效果: 按鍵按下(持續按下), LED0維持點亮, 只要一放開就熄滅.
// 開發板上的4個獨立按鍵 {INT0, INT1, T0, T1}, 分別對應到 {P3_2, P3_3, P3_4, P3_5}
// 練習1: 試著使用其他按鍵
// 練習2: 試著做出一個
#define LED0 P1_bit.P1_0
#define BTN1 P3_bit.P3_2
練習2:按一下按鈕就改變LED
48
/****************************************************************************************
Filename: exercise2-02.c
Description: 使用button (這個程式還未使用中斷)
****************************************************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
#define BTN1 P3_bit.P3_2
// 這裡使用全域變數, 當旗標使用, 初始值為0
volatile unsigned char btn_flag = 0;
void main()
{
BTN1 = 1; // I/O要當輸入時,要先寫入1
while(1)
{
if (BTN1 == 0)
btn_flag = ~btn_flag; // 當btn按下, 所有位元反向
if (btn_flag != 0)
LED0 = 0; // 若btn_flag不為0, 就點亮LED0
else
LED0 = 1; // 反之btn_flag若為0, 就熄滅LED0
}
}
// 燒錄完後,試試看, 有沒有發現甚麼很詭異的現象?
volatile unsigned char btn_flag = 0;
Bouncing
+5V
+5V
A
B
49
小錦囊:軟體Debounce小程式
50
if (BTN1 == 0)
{
delayms(50);
if (BTN1 == 0){
while(BTN1 == 0);
btn_flag = ~btn_flag;
}
}
練習3:去抖動
51
/***********************************************************************************
Filename: exercise2-03.c
Description: 使用button / Simple Debounce (這個程式還未使用中斷)
************************************************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
#define BTN1 P3_bit.P3_2
typedef unsigned char uint8;
volatile unsigned char btn_flag = 0;
void delayms(uint8);
void main()
{
BTN1 = 1; // I/O要當輸入時,要先寫入1
while(1)
{
if (BTN1 == 0)
{
delayms(50);
if (BTN1 == 0){
// 這裡好像少了甚麼
btn_flag = ~btn_flag;
}
}
if ((btn_flag & 0x01) == 1)
LED0 = 0;
else
LED0 = 1;
}
}
void delayms(uint8 time)
{
uint8 n;
while(time>0)
{
n = 162;
while(n>0) n--;
time --;
}
}
練習4:以函式包裝對硬體的操作
52
/**********************************************************************
Filename: exercise2-04.c
Description: 使用button / Simple Debounce (這個程式還未使用中斷)
***********************************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
#define BTN1 P3_bit.P3_2
#define BTN_NOT_PRESSED 0
#define BTN_PRESSED 1
#define LED_ON 0
#define LED_OFF 1
typedef unsigned char uint8;
volatile unsigned char btn_flag = 0;
void BTN_Init(void);
uint8 BTN_Get_Input(uint8 debounce_time);
void delayms(uint8);
void main()
{
BTN_Init();
while(1)
{
if( BTN_Get_Input(50) ){
btn_flag = ~btn_flag;
}
LED0 = (btn_flag?LED_ON:LED_OFF);
}
}
void BTN_Init(void)
{
BTN1 = 1; // I/O要當輸入時,要先寫入1
}
uint8 BTN_Get_Input(uint8 debounce_time)
{
uint8 BTN_val = BTN_NOT_PRESSED;
if (BTN1 == 0) {
delayms(debounce_time);
if (BTN1 == 0) {
while(BTN1==0);
BTN_val = BTN_PRESSED;
}
}
return BTN_val; // Return BTN value
}
void delayms(uint8 time)
{
略
}
動態掃描
Lab3:七段顯示器與行列式鍵盤
符號 0 1 2 3 4 5
編碼 0x3F 0x06 0x5B 0x4F 0x66 0x6D
符號 6 7 8 9 A B
編碼 0x7D 0x07 0x7F 0x6F 0x77 0x7C
符號 C D E F 無顯示
編碼 0x39 0x5E 0x79 0x71 0x00
七段顯示器
54
0 1 2 3 4 5 6 7
開發板上的配置
55
pos_set=1;
P0 = 0xFE;
pos_set=0;
seg_set=1;
P0=0x71;
seg_set=0;
靜態顯示與動態顯示
56
範例實習3
 請打開lab3_7seg_keypad
 練習1:靜態顯示一位 (練習: 用按鍵改變顯示位)
 練習2:靜態顯示多位,並隨時間流逝遞增符號
(練習:改用按鍵改變顯示符號)
 練習3:使用動態掃描同時顯示多位7段顯示器
 練習4:掃描式矩陣鍵盤
57
練習1:點亮一顆七段顯示器
58
/*********************************************************************
Filename: exercise3-01.c
Description: 點亮一顆7段顯示器
*********************************************************************/
#include<ioAT89C52.h>
#define seg_set P2_bit.P2_6
#define pos_set P2_bit.P2_7
#define SEG7LED P0
#define POS7LED P0
void main()
{
pos_set = 1;
POS7LED = 0xFE; // 1111,1110
pos_set = 0;
seg_set = 1;
SEG7LED = 0x71; // 0111,0001
seg_set = 0;
while(1);
}
// 練習: 按下按鍵, 依序點亮其他的7段顯示器
練習2:點亮多顆顯示器(I)
59
/*******************************************************************
Filename: exercise3-02.c
Description: 依序顯示符號0, 1,2,3, ->, A, b, C, d, E, F
********************************************************************/
#include<ioAT89C52.h>
#define seg_set P2_bit.P2_6
#define pos_set P2_bit.P2_7
#define SEG7LED P0
#define POS7LED P0
typedef unsigned char uint8;
void DispScrClr(void);
void DispShowPos(uint8 pos);
void DispShowSym(uint8 sym_num, uint8 dp);
void delayms(uint8 time);
// 符號表 0,1,2,...,9, A, b, C, d, E, F
uint8 symbols[]={
0x3F,0x06,0x5B,0x4F,
0x66,0x6D,0x7D,0x07,
0x7F,0x6F,0x77,0x7C,
0x39,0x5E,0x79,0x71};
void main()
{
DispScrClr();
uint8 symbol_num;
while(1)
{
DispShowPos(0xF0); // 1111, 0000 (pos0~3)
for(symbol_num=0;symbol_num<16;symbol_num++)
{
if (symbol_num>5){
DispShowPos(0xE0); // 1110, 0000
DispShowSym(symbol_num, 1);
}else{
DispShowSym(symbol_num, 0);
}
delayms(255);
}
DispScrClr();
delayms(255);
}
}
練習2:點亮多顆顯示器(II)
/**************************************************************************
* @fn DispScrClr
* @brief Clear the Display Screen. Clear all 7-Seg LEDs into blank
* @param None
* @return None
*************************************************************************/
void DispScrClr(void)
{
SEG7LED = 0x00;
seg_set = 1;
seg_set = 0;
POS7LED = 0xFF;
pos_set = 1;
pos_set = 0;
}
/*************************************************************************
* @fn DispShowPos
* @brief Show the Display Screen with assigned positions.
* @param None
* @return None
************************************************************************/
void DispShowPos(uint8 pos)
{
POS7LED = ~pos;
pos_set = 1;
pos_set = 0;
}
/*********************************************************
* @fn DispShowSym
* @brief Show the Symbol with dot-point(dp) or not
********************************************************/
void DispShowSym(uint8 sym_num, uint8 dp)
{
uint8 sym;
if(dp!=0)
sym = symbols[sym_num]|0x80;
else
sym = symbols[sym_num];
SEG7LED = sym;
seg_set = 1;
seg_set = 0;
}
/********************************************************
* @fn delayms
* @brief delay with ms
********************************************************/
void delayms(uint8 time)
{
uint8 n;
while(time>0)
{
n = 162;
while(n>0) n--;
time --;
}
}
60
74HC573栓鎖器
61
動態掃描同時顯示多位7段顯示器
62
pos_set=1;
P0 = 0xFE;
pos_set=0;
seg_set=1;
P0=0x5B;
seg_set=0;
delayms(2);
pos_set=1;
P0 = 0xFD;
pos_set=0;
seg_set=1;
P0=0x7F;
seg_set=0;


練習3:各位依序顯示數字0-7
#define POS(n) (1 << (n)) void DispSym_at_Pos(uint8 pos, uint8 symbol_num, uint8 dp);
/***************************************************************************
* @fn DispSym_at_Pos
* @brief Show the Symbol at specific position with dot-point(dp) or not
* @param None
* @return None
***************************************************************************/
void DispSym_at_Pos(uint8 pos, uint8 symbol_num, uint8 dp)
{
DispShowSym(symbol_num, dp);
DispShowPos(pos);
}
void main()
{
DispScrClr();
uint8 symbol_num = 0;
uint8 pos_num = 0;
while(1)
{
for (pos_num=0;pos_num<8;pos_num++){
DispSym_at_Pos(POS(pos_num),symbol_num,0);
symbol_num++;
if (symbol_num ==8) symbol_num=0;
delayms(250);
}
}
}
63
避免殘影
64
pos_set=1;
P0 = 0xFE;
pos_set=0;
seg_set=1;
P0=0x5B;
seg_set=0;
delayms(2);
seg_set=1;
P0=0x00;
seg_set=0;
delayms(1);



鍵盤鍵值對應
65
key_val keycode_bin keycode_hex
無 1111,0000 0xF0
0 0111,1110 0x7E
1 0111,1101 0x7D
2 0111,1011 0x7B
3 0111,0111 0x77
4 1011,1110 0xBE
5 1011,1101 0xBD
6 1011,1011 0xBB
7 1011,0111 0xB7
8 1101,1110 0xDE
9 1101,1101 0xDD
10 1101,1011 0xDB
11 1101,0111 0xD7
12 1110,1110 0xEE
13 1110,1101 0xED
14 1110,1011 0xEB
15 1110,0111 0xE7
0
4
8
C
1
5
9
D
2
6
A
E
3
7
B
F
P3.0 P3.1 P3.2 P3.3
P3.7
P3.6
P3.5
P3.4
0
4
8
C
1
5
9
D
2
6
A
E
3
7
B
F
P3.0 P3.1 P3.2 P3.3
P3.7
P3.6
P3.5
P3.4
練習4:將按下掃描鍵盤值顯示出來
66
/*********************************************************
Filename: exercise3-04.c
Description: keypad scan
*********************************************************/
#include<ioAT89C52.h>
#define seg_set P2_bit.P2_6
#define pos_set P2_bit.P2_7
#define KeyPort P3
typedef unsigned char uint8;
uint8 KeypadScan(void);
uint8 KeyPushed(uint8 keycode);
volatile uint8 n;
void delayms(uint8 time);
uint8 symbols[]={
0x3F,0x06,0x5B,0x4F,
0x66,0x6D,0x7D,0x07,
0x7F,0x6F,0x77,0x7C,
0x39,0x5E,0x79,0x71};
void main()
{
// use POS4 of 7-seg LED to show the pushed key number
P0=0xEF;
pos_set=1;
pos_set=0;
while(1)
{
KeyPort = 0xF0; // H4-1(input), L4-0(output)
if(KeyPort!=0xF0) {
delayms(25);
n = KeyPushed(KeypadScan());
}
if(n!=0xFF) {
P0=symbols[n];
seg_set=1;
seg_set=0;
}else{
P0=0x00;
seg_set=1;
seg_set=0;
}
}
}
uint8 KeypadScan(void)
{
uint8 key_code;
KeyPort = 0xFE; // 1111,1110: check col_1
if(KeyPort != 0xFE) {
key_code = (KeyPort & 0xF0)|0x0E;
delayms(1);
return key_code;
}
KeyPort = 0xFD; // 1111,1101: check col_2
if(KeyPort != 0xFD) {
key_code = (KeyPort & 0xF0)|0x0D;
delayms(1);
return key_code;
}
KeyPort = 0xFB; // 1111, 1011: check col_3
if(KeyPort != 0xFB) {
key_code = (KeyPort & 0xF0)|0x0B;
delayms(1);
return key_code;
}
KeyPort = 0xF7; // 1111, 0111: check col_4
if(KeyPort != 0xF7) {
key_code = (KeyPort & 0xF0)|0x07;
delayms(1);
return key_code;
}
return 0xFF;
}
uint8 KeyPushed(uint8 keycode)
{
switch(keycode)
{
case 0x7E: return 0; break;
case 0x7D: return 1; break;
case 0x7B: return 2; break;
case 0x77: return 3; break;
case 0xBE: return 4; break;
case 0xBD: return 5; break;
case 0xBB: return 6; break;
case 0xB7: return 7; break;
case 0xDE: return 8; break;
case 0xDD: return 9; break;
case 0xDB: return 10; break;
case 0xD7: return 11; break;
case 0xEE: return 12; break;
case 0xED: return 13; break;
case 0xEB: return 14; break;
case 0xE7: return 15; break;
default: return 0xFF; break;
}
}
void delayms(uint8 time)
{
uint8 n;
while(time>0)
{
n = 162;
while(n>0) n--;
time --;
}
}
67
控制外部電路模組
Lab4:液晶顯示模組(LCM)
1602A LCM模組
RS R/W 作用
0 0 將指令碼寫入IR(指令暫存器),並執行指令。
0 1 讀取BF(DB7)與位址計數器AC(DB0~6)內容。
1 0
將資料寫入DR(資料暫存器)。
LCM內部自動執行DR->DD RAM或DR->CG RAM。
1 1
讀取DR之資料。
LCM內部自動執行DD RAM->或CG RAM->DR。
69
MC
U
字元圖形顯示到螢幕的過程
70
‘I’, ‘ ’, ‘a’, ‘m’, …
(ASCII)
文字擺放的
起始位置 I a m a t e a c h e
只要指定起始位置,每個字元寫入
後,AC就會自動累加(減),因此所
有字元就會依序顯示出來。
標準字符庫(字元產生器CGROM)
71
CG RAM (自製字元圖形)
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};
/**********************************************************
* @fn LCD_DefChar
* @brief This function help you define your own pattern
* @param uint8 id: offset of the CGRAM, uint8 *pat points
* to the pattern table (array).
* @return None
***********************************************************/
void LCD_DefChar(uint8 id, uint8 *pat)
{
uint8 i;
LCD_CmdWr(0x40 + ( id<<3 )); // Set address of CGRAM
for(i=0;i<8;i++){
LCD_DataWr(*pat++);
}
}
72
LCM共有11種指令
73
指令
動作
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
執行
時間
功能設定 0 0 0 0 1 DL(1) N(2) F(3) X X 40 us
清除顯示器 0 0 0 0 0 0 0 0 0 1 1.64ms
游標回左上角 0 0 0 0 0 0 0 0 1 X 40 us
設定輸入模式 0 0 0 0 0 0 0 1 I/D(4) S(4) 40 us
螢幕開或關 0 0 0 0 0 0 1 D C B 40 us
游標/顯示移位 0 0 0 0 0 1 S/C(5) R/L(5) X X 40 us
設定CGRAM地址 0 0 0 1 A A A A A A 40 us
設定DDRAM地址 0 0 1 A A A A A A A 40 us
讀取BF與地址 0 1 BF(6) A A A A A A A 40 us
寫資料至RAM 1 0 D D D D D D D D 40 us
從RAM讀資料 1 1 D D D D D D D D 40 us
日立HD44780相容LCD之常用指令表
74
No. Instruction Hex Decimal
1 Function Set: 8-bit, 1 Line, 5x7 Dots 0x30 48
2 Function Set: 8-bit, 2 Line, 5x7 Dots 0x38 56
3 Function Set: 4-bit, 1 Line, 5x7 Dots 0x20 32
4 Function Set: 4-bit, 2 Line, 5x7 Dots 0x28 40
5 Entry Mode 0x06 6
6
Display off Cursor off
(clearing display without clearing DDRAM content)
0x08 8
7 Display on Cursor on 0x0E 14
8 Display on Cursor off 0x0C 12
9 Display on Cursor blinking 0x0F 15
10 Shift entire display left 0x18 24
12 Shift entire display right 0x1C 30
13 Move cursor left by one character 0x10 16
14 Move cursor right by one character 0x14 20
15 Clear Display (also clear DDRAM content) 0x01 1
16 Set DDRAM address or cursor position on display 0x80+add 128+add
17 Set CGRAM address or set pointer to CGRAM location 0x40+add 64+add
讀取時序圖
75
寫入時序圖
76
實習4
77
 練習1:撰寫LCM驅動程式,系統開機於螢幕顯示
字串,按下按鍵改變顯示字串內容。
 練習2:螢幕的動態效果
 練習3:使用自訂圖形。進度條的製作。
練習1:撰寫LCM驅動程式
78
#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
/* HD44780 Commands */
#define LCD_CMD_CLS 0x01
#define LCD_CMD_FNCT 0x38 // 16*2 display, 5*7 bitmap, 8-bits data port
#define LCD_CMD_MODE 0x06 // after R/W one char, addr+1, cursor+1
#define LCD_CMD_ON_OFF 0x0C // Enable LCD, Cursor OFF, No Blink Cursor
typedef unsigned char uint8;
79
static uint8 LCD_MaxCols;
static uint8 LCD_MaxRows;
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};
char StrL1[]="LCD 1602 Test";
char StrL2[]="OK";
static void LCD_CursorSet(uint8 row, uint8 col);
void LCD_DataWr(uint8 data);
void LCD_CmdWr(uint8 cmd);
void LCD_Init(uint8 maxrows, uint8 maxcols);
void LCD_DispChar(uint8 row, uint8 col, char c);
void LCD_DispStr(uint8 row, uint8 col, char *s);
void LCD_ClrLine(uint8 line);
void LCD_ClrScr(void);
void LCD_DefChar(uint8 id, uint8 *pat);
void LCD_DispHorBarInit(void);
void LCD_DispHorBar(uint8 row, uint8 col, uint8 val);
void delayms(uint8 time);
80
/**********************************************************************************
* @fn LCD_Init
* @brief LCD Initilization
* @param uint8 maxrows: max number of rows, uint8 maxcols: max number of columns
* @return None
**********************************************************************************/
void LCD_Init(uint8 maxrows, uint8 maxcols)
{
LCD_MaxCols = maxcols;
LCD_MaxRows = maxrows;
delayms(30);
LCD_EN = 0;
LCD_RS = 0;
LCD_RW = 0;
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_ON_OFF);
LCD_CmdWr(LCD_CMD_MODE);
LCD_CmdWr(LCD_CMD_CLS);
delayms(2);
}
/*****************************************
* @fn LCD_CmdWr
* @brief Write a command to the LCD
* @param uint8 cmd: the command
* @return None
*****************************************/
void LCD_CmdWr(uint8 cmd)
{
delayms(1);
LCD_RS = LCD_SEL_CMD;
LCD_RW = LCD_IO_WRITE;
LCD_DATA_PORT = cmd;
delayms(1);
LCD_EN = 1;
delayms(1);
LCD_EN = 0;
}
81
/*******************************************************************************************
* @fn LCD_ClrLine
* @brief Clear a certain line
* @param uint8 line: 1 is the first line, and 2 is the second line
* @return None
******************************************************************************************/
void LCD_ClrLine(uint8 line)
{
uint8 i;
if(line < LCD_MaxRows)
{
LCD_CursorSet(line, 0);
for(i=0;i<LCD_MaxCols;i++){
LCD_DataWr(' ');
}
LCD_CursorSet(line, 0);
}
}
/************************************
* @fn LCD_ClrScr
* @brief Clear whole screen
* @param None
* @return None
***********************************/
void LCD_ClrScr(void)
{
LCD_CmdWr(LCD_CMD_CLS);
}
/***********************************************
* @fn LCD_DataWr
* @brief Write a data to the LCD
* @param uint8 data: the data
* @return None
**********************************************/
void LCD_DataWr(uint8 data)
{
delayms(1);
LCD_RS = LCD_SEL_DATA;
LCD_RW = LCD_IO_WRITE;
LCD_DATA_PORT = data;
delayms(1);
LCD_EN = 1;
delayms(1);
LCD_EN = 0;
}
82
/***********************************************************************************
* @fn LCD_CursorSet
* @brief Set the position of the cursor
* @param (uint8 row, uint8 col) sets the position
* @return None
**********************************************************************************/
static void LCD_CursorSet(uint8 row, uint8 col)
{
switch(row){
case 0:
if(LCD_MaxRows==1){
if (col < (LCD_MaxCols >> 1)) // If used only one line LCD
LCD_CmdWr(0x80 + col); // First half of line starts at 0x80
else // Second half of line starts at 0xC0
LCD_CmdWr(0xC0 + col - (LCD_MaxCols >> 1));
}else{
LCD_CmdWr(0x80 + col); // select line 1
}
break;
case 1:
LCD_CmdWr(0xC0 + col); // select line 2
break;
case 2:
LCD_CmdWr(0x80 + LCD_MaxCols + col); // select line 3
break;
case 3:
LCD_CmdWr(0xC0 + LCD_MaxCols + col); // select line 4
break;
}
}
83
/*************************************************************************************
* @fn LCD_DispChar
* @brief Show a character at specific postion
* @param (uint8 row, uint8 col) is the postion, and char c: the character to show
* @return None
************************************************************************************/
void LCD_DispChar(uint8 row, uint8 col, char c)
{
if(row < LCD_MaxRows && col < LCD_MaxCols)
{
LCD_CursorSet(row, col);
LCD_DataWr(c);
}
}
/***********************************************************************************
* @fn LCD_DispStr
* @brief Display a string from a specific position
* @param (uint8 row, uint8 col) sets the position and char *s is the string
* @return None
*********************************************************************************/
void LCD_DispStr(uint8 row, uint8 col, char *s)
{
uint8 i;
if(row < LCD_MaxRows && col < LCD_MaxCols){
LCD_CursorSet(row, col);
i = col;
while( i < LCD_MaxCols && *s){
LCD_DataWr(*s++);
i++;
}
}
}
/***************************************************************************************************
* @fn LCD_DispHorBar
* @brief Display the horizon bar
* @param (uint8 row, uint8 col) sets the position, uint8 val sets the value of full (100%)
* @return None
***************************************************************************************************/
void LCD_DispHorBar(uint8 row, uint8 col, uint8 val)
{
uint8 i, full, frac;
full = val/5; // how many full blocks to turn on
frac = val%5; // portion of block
if(row < LCD_MaxRows && (col + full -1) < LCD_MaxCols){
i = 0;
LCD_CursorSet(row, col);
while(full > 0)
{
LCD_DataWr(5); // Send Custom character #5, which is full block
i++;
full--;
}
if(frac>0){
LCD_DataWr(frac); // custom char #frac
}
}
}
/**************************************
* @fn LCD_DispHorBarInit
* @brief HorizonBar Initilize
* @param None
* @return None
*************************************/
void LCD_DispHorBarInit(void)
{
LCD_DefChar(1, &LCD_DispBar1[0]);
LCD_DefChar(2, &LCD_DispBar2[0]);
LCD_DefChar(3, &LCD_DispBar3[0]);
LCD_DefChar(4, &LCD_DispBar4[0]);
LCD_DefChar(5, &LCD_DispBar5[0]);
}
84
85
/**********************************************************
* @fn LCD_DefChar
* @brief This function help you define your own pattern
* @param uint8 id: offset of the CGRAM, uint8 *pat points
* to the pattern table (array).
* @return None
***********************************************************/
void LCD_DefChar(uint8 id, uint8 *pat)
{
uint8 i;
LCD_CmdWr(0x40 + ( id<<3 )); // Set address of CGRAM
for(i=0;i<8;i++){
LCD_DataWr(*pat++);
}
}
/********************************************************
* @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 --;
}
}
86
void main()
{
LCD_Init(2, 16);
LCD_DispStr(0,0,StrL1);
LCD_DispStr(1,0,StrL2);
BTN1 = 1;
BTN2 = 1;
while(1)
{
if (BTN1 == 0) {
delayms(50);
if (BTN1 == 0) {
while(BTN1 == 0);
LCD_ClrScr();
}
LCD_DispStr(0,0,StrL1);
}
if (BTN2 == 0) {
delayms(50);
if (BTN2 == 0) {
while(BTN2 == 0);
LCD_ClrScr();
LCD_DispStr(1,0,"ROW1, COL0");
LCD_DispStr(0,1,"ROW0, COL1");
}
}
}
}
練習2:動態效果
87
void main()
{
uint8 i = 0, j;
BTN1 = 1;
char *str1 = "Dynamic Show";
char *str2 = "rolling text";
LCD_Init(2, 16);
LCD_DispStr(0, 0, StrL1);
for(j=0;j<3;j++) { delayms(250); }
LCD_DispStr(1, 0, StrL2);
for(j=0;j<8;j++) { delayms(250); }
LCD_ClrScr();
delayms(2);
LCD_DispStr(0, 0, str1);
for(j=0;j<16;j++) {
LCD_CmdWr(0x1C);
delayms(250);
}
for(j=0;j<16;j++) {
LCD_CmdWr(0x18);
delayms(250);
}
delayms(250);
while(1)
{
if (BTN1 == 0) {
delayms(50);
if (BTN1 == 0) {
while(BTN1 == 0);
LCD_ClrLine(0);
while(*(str2+i)) {
LCD_DispChar(0, i, *(str2+i));
i++;
delayms(200);
}
i=0;
}
}
}
}
練習3:進度條製作
88
void main()
{
uint8 i, percent_bar;
char num[4];
BTN1 = 1;
char *str1 = "Dynamic Show";
LCD_Init(2, 16);
LCD_DispHorBarInit();
LCD_DispStr(0, 0, str1);
while(1)
{
if (BTN1 == 0) {
delayms(50);
if (BTN1 == 0) {
while(BTN1 == 0);
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);
}
}
}
}
}
中斷系統
Lab5: 使用按鍵引發中斷
中斷的概念
RETI
……
90
中斷的優缺點
 優點:
1) 解決快速主機與慢速I/O設備的資料傳送問題。
2) CPU可分時為多個I/O設備服務,提高電腦利用率。
3) 即時性。
4) 可處理設備故障及掉電等突發事件,使系統可靠性提高。
 缺點:
1) ISR程式不可執行太久
2) 不可於ISR中呼叫太多函式
3) 有critical section的問題
4) 不能呼叫不可重進入函式
5) 巢狀中斷可能使堆疊溢位
91
C51中斷結構:暫存器IE/TCON/IP
EX0 EA PX0
0
1
ET0 PT0
0
1
EX1 PX1
0
1
ET1 PT1
0
1
ES PS
0
1
≥1
RI
TI
SCON
TCON
IE0
TF0
IE1
TF1
10
1
0
1
IT0
IT1
INT0
INT1
T0
T1
RX
TX
IE IP
1
11
1
1
1
1
1
0
92
中斷入口
/* Interrupt Vectors */
#define extern0 0x03 /* External interrupt 0 */
#define IE0_int 0x03 /* External interrupt 0 */
#define timer0 0x0B /* Timer 0 Interrupt */
#define TF0_int 0x0B /* Timer 0 Interrupt */
#define extern1 0x13 /* External interrupt 1 */
#define IE1_int 0x13 /* External interrupt 1 */
#define timer1 0x1B /* Timer 1 Interrupt */
#define TF1_int 0x1B /* Timer 1 Interrupt */
...
中斷源 中斷旗標 ISR入口 優先權
外部中斷0 IE0 0x0003 高
定時/計數器0 (T0) TF0 0x000B
外部中斷1 IE1 0x0013
定時/計數器0 (T1) TF1 0x001B
串列埠 RI或TI 0x0023 低
93
範例實習5
 請打開lab5_Interrupt
 練習1: 外部中斷0
 練習2: 觀察中斷打斷目前工作
 練習3: 優先權的設置
 練習4: 在ISR中更改全域變數的問題
 練習5: 在ISR中使用不可重進入函式的問題
94
練習1:使用外部中斷0
95
/************************************************************************************
Filename: exercise5-01.c
Description: 使用button引發中斷, 按壓BTN1以點亮或熄滅LED0
開發板按鍵{INT0, INT1, T0, T1}, 分別對應到 {P3_2, P3_3, P3_4, P3_5}
*************************************************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
#define BTN1 P3_bit.P3_2
typedef unsigned char uint8;
void delayms(uint8);
void main()
{
BTN1 = 1; // I/O要當輸入時,要先寫入1
LED0 = 1;
TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標設為0
IE_bit.EX0 = 1; // 外部中斷0致能
IE_bit.EA = 1; // 總中斷致能
while(1)
{
;
}
}
void delayms(uint8 time)
{
uint8 n;
while(time>0)
{
n = 162;
while(n>0) n--;
time --;
}
}
/* Symbol defined in I/O header file */
#pragma vector = extern0
__interrupt void Int_Extern0(void)
{
LED0 = ~LED0;
TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標清為0
}
// 如果按壓按鈕的效果不好, 請加入debounce程式
// 練習: 改以外部中斷1實作
練習2:中斷會打斷當前工作
96
 平時LED1閃爍,按BTN1發生中斷使LED0閃爍10次
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
#define LED1 P1_bit.P1_1
#define BTN1 P3_bit.P3_2
typedef unsigned char uint8;
void delayms(uint8);
void main()
{
BTN1 = 1; // I/O要當輸入時,要先寫入1
LED0 = 1;
LED1 = 1;
TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標設為0
IE_bit.EX0 = 1; // 外部中斷0致能
IE_bit.EA = 1; // 總中斷致能
while(1)
{
delayms(250);
delayms(250);
LED1 = ~LED1;
}
}
#pragma vector = extern0
__interrupt void Int_Extern0(void)
{
uint8 i;
for(i=0;i<20;i++){
LED0 = ~LED0;
delayms(250);
}
TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標清為0
}
練習3:優先權
97
 LED3平時閃爍,按BTN1, LED0閃10次, BTN2則LED1
快閃15次
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
#define LED1 P1_bit.P1_1
#define LED2 P1_bit.P1_2
#define BTN1 P3_bit.P3_2
#define BTN2 P3_bit.P3_3
typedef unsigned char uint8;
void delayms(uint8);
void main()
{
BTN1 = 1;
BTN2 = 1;
LED0 = 1;
LED1 = 1;
TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標設為0
IE_bit.EX0 = 1; // 外部中斷0致能
IP_bit.PX0 = 1;
IP_bit.PX1 = 0;
TCON_bit.IE1 = 0; // 外部中斷1的中斷旗標設為0
IE_bit.EX1 = 1; // 外部中斷1致能
IE_bit.EA = 1; // 總中斷致能
while(1)
{
delayms(250);
delayms(250);
LED2 = ~LED2;
}
}
void delayms(uint8 time)
{
uint8 n;
while(time>0)
{
n = 162;
while(n>0) n--;
time --;
}
}
#pragma vector = extern0
__interrupt void Int_Extern0(void)
{
uint8 i;
for(i=0;i<20;i++){
LED0 = ~LED0;
delayms(250);
}
TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標清為0
}
#pragma vector = extern1
__interrupt void Int_Extern1(void)
{
uint8 i;
for(i=0;i<30;i++){
LED1 = ~LED1;
delayms(100);
}
TCON_bit.IE1 = 0; // 外部中斷1的中斷旗標清為0
}
練習4:全域變數
98
 BTN2按完更改gflag以決定LED1之亮滅
typedef unsigned char uint8;
volatile uint8 gflag = 0;
void delayms(uint8);
#pragma vector = extern0
__interrupt void Int_Extern0(void)
{
uint8 i;
for(i=0;i<20;i++){
LED0 = ~LED0;
delayms(250);
}
// gflag = ~gflag;
TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標清為0
}
#pragma vector = extern1
__interrupt void Int_Extern1(void)
{
uint8 i;
for(i=0;i<30;i++){
LED1 = ~LED1;
delayms(100);
}
gflag = ~gflag;
TCON_bit.IE1 = 0; // 外部中斷1的中斷旗標清為0
}
#pragma vector = extern0
__interrupt void Int_Extern0(void)
{
IE_bit.EA = 0;
uint8 i;
for(i=0;i<20;i++){
LED0 = ~LED0;
delayms(250);
}
gflag = ~gflag;
TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標清為0
IE_bit.EA = 1;
}
#pragma vector = extern1
__interrupt void Int_Extern1(void)
{
IE_bit.EA = 0;
uint8 i;
for(i=0;i<30;i++){
LED1 = ~LED1;
delayms(100);
}
gflag = ~gflag;
TCON_bit.IE1 = 0; // 外部中斷1的中斷旗標清為0
IE_bit.EA = 1;
}
練習5:不可重進入函數
99
/**********************************************************************************
Filename: exercise5-05.c
Description: 不可重進入函數
開發板按鍵{INT0, INT1, T0, T1}, 分別對應到 {P3_2, P3_3, P3_4, P3_5}
************************************************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
#define LED1 P1_bit.P1_1
#define LED2 P1_bit.P1_2
#define BTN1 P3_bit.P3_2
typedef unsigned char uint8;
void delayms(uint8);
volatile uint8 temp;
void swap(uint8* x, uint8*y);
void main()
{
BTN1 = 1;
LED0 = 1;
LED1 = 1;
TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標設為0
IE_bit.EX0 = 1; // 外部中斷0致能
IE_bit.EA = 1; // 總中斷致能
uint8 a = 1;
uint8 b = 0;
while(1)
{
if(a==1)
LED1 = 0;
else if (a==0)
LED1 = 1;
else
LED2 = 0;
delayms(250);
swap(&a, &b);
}
}
void swap(uint8* x, uint8* y)
{
uint8 i;
temp = *x;
LED0 = 0;
for(i=0;i<10;i++)
delayms(250);
LED0 = 1;
*x = *y;
*y = temp;
}
void delayms(uint8 time)
{
uint8 n;
while(time>0)
{
n = 162;
while(n>0) n--;
time --;
}
}
#pragma vector = extern0
__interrupt void Int_Extern0(void)
{
IE_bit.EA = 0;
uint8 a = 5, b =10;
swap(&a, &b);
TCON_bit.IE0 = 0;
IE_bit.EA = 1;
}

More Related Content

What's hot

電路學 - [第六章] 二階RLC電路
電路學 - [第六章] 二階RLC電路電路學 - [第六章] 二階RLC電路
電路學 - [第六章] 二階RLC電路Simen Li
 
XilinxのxsimでSoftware Driven Verification.pdf
XilinxのxsimでSoftware  Driven Verification.pdfXilinxのxsimでSoftware  Driven Verification.pdf
XilinxのxsimでSoftware Driven Verification.pdfMr. Vengineer
 
System Verilog (Tutorial -- 4X1 Multiplexer)
System Verilog (Tutorial -- 4X1 Multiplexer)System Verilog (Tutorial -- 4X1 Multiplexer)
System Verilog (Tutorial -- 4X1 Multiplexer)Denise Wilson
 
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack FirmwareSimen Li
 
二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ
二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ
二分探索法で作る再帰呼び出しできるCプリプロセッサマクロdigitalghost
 
Verilator勉強会 2021/05/29
Verilator勉強会 2021/05/29Verilator勉強会 2021/05/29
Verilator勉強会 2021/05/29ryuz88
 
射頻電子 - [實驗第二章] I/O電路設計
射頻電子 - [實驗第二章] I/O電路設計射頻電子 - [實驗第二章] I/O電路設計
射頻電子 - [實驗第二章] I/O電路設計Simen Li
 
/proc/irq/&lt;irq>/smp_affinity
/proc/irq/&lt;irq>/smp_affinity/proc/irq/&lt;irq>/smp_affinity
/proc/irq/&lt;irq>/smp_affinityTakuya ASADA
 
VerilatorとSystemCでSoftware Driven Verification
VerilatorとSystemCでSoftware Driven VerificationVerilatorとSystemCでSoftware Driven Verification
VerilatorとSystemCでSoftware Driven VerificationMr. Vengineer
 
Verilog 語法教學
Verilog 語法教學 Verilog 語法教學
Verilog 語法教學 艾鍗科技
 
射頻電子 - [第二章] 傳輸線理論
射頻電子 - [第二章] 傳輸線理論射頻電子 - [第二章] 傳輸線理論
射頻電子 - [第二章] 傳輸線理論Simen Li
 
Popcntによるハミング距離計算
Popcntによるハミング距離計算Popcntによるハミング距離計算
Popcntによるハミング距離計算Norishige Fukushima
 
專題製作發想與報告撰寫技巧
專題製作發想與報告撰寫技巧專題製作發想與報告撰寫技巧
專題製作發想與報告撰寫技巧Simen Li
 
Real Time Clock Interfacing with FPGA
Real Time Clock Interfacing with FPGAReal Time Clock Interfacing with FPGA
Real Time Clock Interfacing with FPGAMafaz Ahmed
 

What's hot (20)

電路學 - [第六章] 二階RLC電路
電路學 - [第六章] 二階RLC電路電路學 - [第六章] 二階RLC電路
電路學 - [第六章] 二階RLC電路
 
XilinxのxsimでSoftware Driven Verification.pdf
XilinxのxsimでSoftware  Driven Verification.pdfXilinxのxsimでSoftware  Driven Verification.pdf
XilinxのxsimでSoftware Driven Verification.pdf
 
System Verilog (Tutorial -- 4X1 Multiplexer)
System Verilog (Tutorial -- 4X1 Multiplexer)System Verilog (Tutorial -- 4X1 Multiplexer)
System Verilog (Tutorial -- 4X1 Multiplexer)
 
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
 
二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ
二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ
二分探索法で作る再帰呼び出しできるCプリプロセッサマクロ
 
Verilator勉強会 2021/05/29
Verilator勉強会 2021/05/29Verilator勉強会 2021/05/29
Verilator勉強会 2021/05/29
 
射頻電子 - [實驗第二章] I/O電路設計
射頻電子 - [實驗第二章] I/O電路設計射頻電子 - [實驗第二章] I/O電路設計
射頻電子 - [實驗第二章] I/O電路設計
 
/proc/irq/&lt;irq>/smp_affinity
/proc/irq/&lt;irq>/smp_affinity/proc/irq/&lt;irq>/smp_affinity
/proc/irq/&lt;irq>/smp_affinity
 
Arduino程式除錯
Arduino程式除錯Arduino程式除錯
Arduino程式除錯
 
VerilatorとSystemCでSoftware Driven Verification
VerilatorとSystemCでSoftware Driven VerificationVerilatorとSystemCでSoftware Driven Verification
VerilatorとSystemCでSoftware Driven Verification
 
Crash course in verilog
Crash course in verilogCrash course in verilog
Crash course in verilog
 
Verilog 語法教學
Verilog 語法教學 Verilog 語法教學
Verilog 語法教學
 
電路學第六章-2
電路學第六章-2電路學第六章-2
電路學第六章-2
 
射頻電子 - [第二章] 傳輸線理論
射頻電子 - [第二章] 傳輸線理論射頻電子 - [第二章] 傳輸線理論
射頻電子 - [第二章] 傳輸線理論
 
5. DFT.pptx
5. DFT.pptx5. DFT.pptx
5. DFT.pptx
 
ATPG flow chart
ATPG flow chart ATPG flow chart
ATPG flow chart
 
Popcntによるハミング距離計算
Popcntによるハミング距離計算Popcntによるハミング距離計算
Popcntによるハミング距離計算
 
VerilatorとSystemC
VerilatorとSystemCVerilatorとSystemC
VerilatorとSystemC
 
專題製作發想與報告撰寫技巧
專題製作發想與報告撰寫技巧專題製作發想與報告撰寫技巧
專題製作發想與報告撰寫技巧
 
Real Time Clock Interfacing with FPGA
Real Time Clock Interfacing with FPGAReal Time Clock Interfacing with FPGA
Real Time Clock Interfacing with FPGA
 

Viewers also liked

RF Module Design - [Chapter 4] Transceiver Architecture
RF Module Design - [Chapter 4] Transceiver ArchitectureRF Module Design - [Chapter 4] Transceiver Architecture
RF Module Design - [Chapter 4] Transceiver ArchitectureSimen Li
 
RF Module Design - [Chapter 2] Noises
RF Module Design - [Chapter 2] NoisesRF Module Design - [Chapter 2] Noises
RF Module Design - [Chapter 2] NoisesSimen Li
 
Multiband Transceivers - [Chapter 1]
Multiband Transceivers - [Chapter 1] Multiband Transceivers - [Chapter 1]
Multiband Transceivers - [Chapter 1] Simen Li
 
Multiband Transceivers - [Chapter 5] Software-Defined Radios
Multiband Transceivers - [Chapter 5]  Software-Defined RadiosMultiband Transceivers - [Chapter 5]  Software-Defined Radios
Multiband Transceivers - [Chapter 5] Software-Defined RadiosSimen Li
 
RF Module Design - [Chapter 1] From Basics to RF Transceivers
RF Module Design - [Chapter 1] From Basics to RF TransceiversRF Module Design - [Chapter 1] From Basics to RF Transceivers
RF Module Design - [Chapter 1] From Basics to RF TransceiversSimen Li
 
[ZigBee 嵌入式系統] ZigBee 應用實作 - 使用 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee 應用實作 - 使用 TI Z-Stack Firmware[ZigBee 嵌入式系統] ZigBee 應用實作 - 使用 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee 應用實作 - 使用 TI Z-Stack FirmwareSimen Li
 
RF Module Design - [Chapter 7] Voltage-Controlled Oscillator
RF Module Design - [Chapter 7] Voltage-Controlled OscillatorRF Module Design - [Chapter 7] Voltage-Controlled Oscillator
RF Module Design - [Chapter 7] Voltage-Controlled OscillatorSimen Li
 
RF Module Design - [Chapter 3] Linearity
RF Module Design - [Chapter 3]  LinearityRF Module Design - [Chapter 3]  Linearity
RF Module Design - [Chapter 3] LinearitySimen Li
 
Multiband Transceivers - [Chapter 2] Noises and Linearities
Multiband Transceivers - [Chapter 2]  Noises and LinearitiesMultiband Transceivers - [Chapter 2]  Noises and Linearities
Multiband Transceivers - [Chapter 2] Noises and LinearitiesSimen Li
 
Multiband Transceivers - [Chapter 3] Basic Concept of Comm. Systems
Multiband Transceivers - [Chapter 3]  Basic Concept of Comm. SystemsMultiband Transceivers - [Chapter 3]  Basic Concept of Comm. Systems
Multiband Transceivers - [Chapter 3] Basic Concept of Comm. SystemsSimen Li
 
RF Module Design - [Chapter 5] Low Noise Amplifier
RF Module Design - [Chapter 5]  Low Noise AmplifierRF Module Design - [Chapter 5]  Low Noise Amplifier
RF Module Design - [Chapter 5] Low Noise AmplifierSimen Li
 
ADF4113 Frequency Synthesizer 驅動程式實作
ADF4113 Frequency Synthesizer 驅動程式實作ADF4113 Frequency Synthesizer 驅動程式實作
ADF4113 Frequency Synthesizer 驅動程式實作Simen Li
 
RF Module Design - [Chapter 8] Phase-Locked Loops
RF Module Design - [Chapter 8] Phase-Locked LoopsRF Module Design - [Chapter 8] Phase-Locked Loops
RF Module Design - [Chapter 8] Phase-Locked LoopsSimen Li
 
RF Module Design - [Chapter 6] Power Amplifier
RF Module Design - [Chapter 6]  Power AmplifierRF Module Design - [Chapter 6]  Power Amplifier
RF Module Design - [Chapter 6] Power AmplifierSimen Li
 
Multiband Transceivers - [Chapter 7] Multi-mode/Multi-band GSM/GPRS/TDMA/AMP...
Multiband Transceivers - [Chapter 7]  Multi-mode/Multi-band GSM/GPRS/TDMA/AMP...Multiband Transceivers - [Chapter 7]  Multi-mode/Multi-band GSM/GPRS/TDMA/AMP...
Multiband Transceivers - [Chapter 7] Multi-mode/Multi-band GSM/GPRS/TDMA/AMP...Simen Li
 
Multiband Transceivers - [Chapter 6] Multi-mode and Multi-band Transceivers
Multiband Transceivers - [Chapter 6] Multi-mode and Multi-band TransceiversMultiband Transceivers - [Chapter 6] Multi-mode and Multi-band Transceivers
Multiband Transceivers - [Chapter 6] Multi-mode and Multi-band TransceiversSimen Li
 
Multiband Transceivers - [Chapter 7] Spec. Table
Multiband Transceivers - [Chapter 7]  Spec. TableMultiband Transceivers - [Chapter 7]  Spec. Table
Multiband Transceivers - [Chapter 7] Spec. TableSimen Li
 
Multiband Transceivers - [Chapter 4] Design Parameters of Wireless Radios
Multiband Transceivers - [Chapter 4] Design Parameters of Wireless RadiosMultiband Transceivers - [Chapter 4] Design Parameters of Wireless Radios
Multiband Transceivers - [Chapter 4] Design Parameters of Wireless RadiosSimen Li
 
射頻電子 - [實驗第四章] 微波濾波器與射頻多工器設計
射頻電子 - [實驗第四章] 微波濾波器與射頻多工器設計射頻電子 - [實驗第四章] 微波濾波器與射頻多工器設計
射頻電子 - [實驗第四章] 微波濾波器與射頻多工器設計Simen Li
 
射頻電子 - [實驗第三章] 濾波器設計
射頻電子 - [實驗第三章] 濾波器設計射頻電子 - [實驗第三章] 濾波器設計
射頻電子 - [實驗第三章] 濾波器設計Simen Li
 

Viewers also liked (20)

RF Module Design - [Chapter 4] Transceiver Architecture
RF Module Design - [Chapter 4] Transceiver ArchitectureRF Module Design - [Chapter 4] Transceiver Architecture
RF Module Design - [Chapter 4] Transceiver Architecture
 
RF Module Design - [Chapter 2] Noises
RF Module Design - [Chapter 2] NoisesRF Module Design - [Chapter 2] Noises
RF Module Design - [Chapter 2] Noises
 
Multiband Transceivers - [Chapter 1]
Multiband Transceivers - [Chapter 1] Multiband Transceivers - [Chapter 1]
Multiband Transceivers - [Chapter 1]
 
Multiband Transceivers - [Chapter 5] Software-Defined Radios
Multiband Transceivers - [Chapter 5]  Software-Defined RadiosMultiband Transceivers - [Chapter 5]  Software-Defined Radios
Multiband Transceivers - [Chapter 5] Software-Defined Radios
 
RF Module Design - [Chapter 1] From Basics to RF Transceivers
RF Module Design - [Chapter 1] From Basics to RF TransceiversRF Module Design - [Chapter 1] From Basics to RF Transceivers
RF Module Design - [Chapter 1] From Basics to RF Transceivers
 
[ZigBee 嵌入式系統] ZigBee 應用實作 - 使用 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee 應用實作 - 使用 TI Z-Stack Firmware[ZigBee 嵌入式系統] ZigBee 應用實作 - 使用 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee 應用實作 - 使用 TI Z-Stack Firmware
 
RF Module Design - [Chapter 7] Voltage-Controlled Oscillator
RF Module Design - [Chapter 7] Voltage-Controlled OscillatorRF Module Design - [Chapter 7] Voltage-Controlled Oscillator
RF Module Design - [Chapter 7] Voltage-Controlled Oscillator
 
RF Module Design - [Chapter 3] Linearity
RF Module Design - [Chapter 3]  LinearityRF Module Design - [Chapter 3]  Linearity
RF Module Design - [Chapter 3] Linearity
 
Multiband Transceivers - [Chapter 2] Noises and Linearities
Multiband Transceivers - [Chapter 2]  Noises and LinearitiesMultiband Transceivers - [Chapter 2]  Noises and Linearities
Multiband Transceivers - [Chapter 2] Noises and Linearities
 
Multiband Transceivers - [Chapter 3] Basic Concept of Comm. Systems
Multiband Transceivers - [Chapter 3]  Basic Concept of Comm. SystemsMultiband Transceivers - [Chapter 3]  Basic Concept of Comm. Systems
Multiband Transceivers - [Chapter 3] Basic Concept of Comm. Systems
 
RF Module Design - [Chapter 5] Low Noise Amplifier
RF Module Design - [Chapter 5]  Low Noise AmplifierRF Module Design - [Chapter 5]  Low Noise Amplifier
RF Module Design - [Chapter 5] Low Noise Amplifier
 
ADF4113 Frequency Synthesizer 驅動程式實作
ADF4113 Frequency Synthesizer 驅動程式實作ADF4113 Frequency Synthesizer 驅動程式實作
ADF4113 Frequency Synthesizer 驅動程式實作
 
RF Module Design - [Chapter 8] Phase-Locked Loops
RF Module Design - [Chapter 8] Phase-Locked LoopsRF Module Design - [Chapter 8] Phase-Locked Loops
RF Module Design - [Chapter 8] Phase-Locked Loops
 
RF Module Design - [Chapter 6] Power Amplifier
RF Module Design - [Chapter 6]  Power AmplifierRF Module Design - [Chapter 6]  Power Amplifier
RF Module Design - [Chapter 6] Power Amplifier
 
Multiband Transceivers - [Chapter 7] Multi-mode/Multi-band GSM/GPRS/TDMA/AMP...
Multiband Transceivers - [Chapter 7]  Multi-mode/Multi-band GSM/GPRS/TDMA/AMP...Multiband Transceivers - [Chapter 7]  Multi-mode/Multi-band GSM/GPRS/TDMA/AMP...
Multiband Transceivers - [Chapter 7] Multi-mode/Multi-band GSM/GPRS/TDMA/AMP...
 
Multiband Transceivers - [Chapter 6] Multi-mode and Multi-band Transceivers
Multiband Transceivers - [Chapter 6] Multi-mode and Multi-band TransceiversMultiband Transceivers - [Chapter 6] Multi-mode and Multi-band Transceivers
Multiband Transceivers - [Chapter 6] Multi-mode and Multi-band Transceivers
 
Multiband Transceivers - [Chapter 7] Spec. Table
Multiband Transceivers - [Chapter 7]  Spec. TableMultiband Transceivers - [Chapter 7]  Spec. Table
Multiband Transceivers - [Chapter 7] Spec. Table
 
Multiband Transceivers - [Chapter 4] Design Parameters of Wireless Radios
Multiband Transceivers - [Chapter 4] Design Parameters of Wireless RadiosMultiband Transceivers - [Chapter 4] Design Parameters of Wireless Radios
Multiband Transceivers - [Chapter 4] Design Parameters of Wireless Radios
 
射頻電子 - [實驗第四章] 微波濾波器與射頻多工器設計
射頻電子 - [實驗第四章] 微波濾波器與射頻多工器設計射頻電子 - [實驗第四章] 微波濾波器與射頻多工器設計
射頻電子 - [實驗第四章] 微波濾波器與射頻多工器設計
 
射頻電子 - [實驗第三章] 濾波器設計
射頻電子 - [實驗第三章] 濾波器設計射頻電子 - [實驗第三章] 濾波器設計
射頻電子 - [實驗第三章] 濾波器設計
 

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

Sy03091说明书
Sy03091说明书Sy03091说明书
Sy03091说明书guest8f3690
 
Phoenix Phdebug
Phoenix PhdebugPhoenix Phdebug
Phoenix Phdebugjainfug
 
S3 cev40getting startv2.1 cn
S3 cev40getting startv2.1 cnS3 cev40getting startv2.1 cn
S3 cev40getting startv2.1 cnVidur Garg
 
Tiptop gp 5.1 setup_instructions
Tiptop gp 5.1 setup_instructionsTiptop gp 5.1 setup_instructions
Tiptop gp 5.1 setup_instructionsguest994aeb5
 
STM32F4 for 智慧型電動輪椅系統Part1
STM32F4 for 智慧型電動輪椅系統Part1STM32F4 for 智慧型電動輪椅系統Part1
STM32F4 for 智慧型電動輪椅系統Part1Jack Wang
 
嵌入式inux應用專題文件-智慧家庭系統
嵌入式inux應用專題文件-智慧家庭系統嵌入式inux應用專題文件-智慧家庭系統
嵌入式inux應用專題文件-智慧家庭系統艾鍗科技
 
Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)FLASH开发者交流会
 
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)Shanda innovation institute
 
Device Driver - Chapter 6字元驅動程式的進階作業
Device Driver - Chapter 6字元驅動程式的進階作業Device Driver - Chapter 6字元驅動程式的進階作業
Device Driver - Chapter 6字元驅動程式的進階作業ZongYing Lyu
 
用Raspberry PI學Linux驅動程式
用Raspberry PI學Linux驅動程式用Raspberry PI學Linux驅動程式
用Raspberry PI學Linux驅動程式Stanley Ho
 
Deployment instruction tg4100 f-ig_cn
Deployment instruction tg4100 f-ig_cnDeployment instruction tg4100 f-ig_cn
Deployment instruction tg4100 f-ig_cnahnlabchina
 
Ch1 系统启动
Ch1 系统启动Ch1 系统启动
Ch1 系统启动guest4d1b8c
 
LinkIt Smart 7688程式開發
LinkIt Smart 7688程式開發LinkIt Smart 7688程式開發
LinkIt Smart 7688程式開發Wei-Tsung Su
 

Similar to [嵌入式系統] MCS-51 實驗 - 使用 IAR (1) (20)

Sy03091说明书
Sy03091说明书Sy03091说明书
Sy03091说明书
 
Phoenix Phdebug
Phoenix PhdebugPhoenix Phdebug
Phoenix Phdebug
 
S3 cev40getting startv2.1 cn
S3 cev40getting startv2.1 cnS3 cev40getting startv2.1 cn
S3 cev40getting startv2.1 cn
 
Tiptop gp 5.1 setup_instructions
Tiptop gp 5.1 setup_instructionsTiptop gp 5.1 setup_instructions
Tiptop gp 5.1 setup_instructions
 
Step7
Step7Step7
Step7
 
STM32F4 for 智慧型電動輪椅系統Part1
STM32F4 for 智慧型電動輪椅系統Part1STM32F4 for 智慧型電動輪椅系統Part1
STM32F4 for 智慧型電動輪椅系統Part1
 
嵌入式inux應用專題文件-智慧家庭系統
嵌入式inux應用專題文件-智慧家庭系統嵌入式inux應用專題文件-智慧家庭系統
嵌入式inux應用專題文件-智慧家庭系統
 
Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)Avm2虚拟机浅析与as3性能优化(陈士凯)
Avm2虚拟机浅析与as3性能优化(陈士凯)
 
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
[Flash开发者交流][2010.05.30]avm2虚拟机浅析与as3性能优化(陈士凯)
 
Stm32 technical slide_pdf
Stm32 technical slide_pdfStm32 technical slide_pdf
Stm32 technical slide_pdf
 
Device Driver - Chapter 6字元驅動程式的進階作業
Device Driver - Chapter 6字元驅動程式的進階作業Device Driver - Chapter 6字元驅動程式的進階作業
Device Driver - Chapter 6字元驅動程式的進階作業
 
用Raspberry PI學Linux驅動程式
用Raspberry PI學Linux驅動程式用Raspberry PI學Linux驅動程式
用Raspberry PI學Linux驅動程式
 
Deployment instruction tg4100 f-ig_cn
Deployment instruction tg4100 f-ig_cnDeployment instruction tg4100 f-ig_cn
Deployment instruction tg4100 f-ig_cn
 
Plc4
Plc4Plc4
Plc4
 
19 cpu03
19 cpu0319 cpu03
19 cpu03
 
Ch1 系统启动
Ch1 系统启动Ch1 系统启动
Ch1 系统启动
 
Arduino AMA中級認證術科實作 all
Arduino AMA中級認證術科實作 allArduino AMA中級認證術科實作 all
Arduino AMA中級認證術科實作 all
 
最终版
最终版最终版
最终版
 
LinkIt Smart 7688程式開發
LinkIt Smart 7688程式開發LinkIt Smart 7688程式開發
LinkIt Smart 7688程式開發
 
Banquet 09
Banquet 09Banquet 09
Banquet 09
 

More from Simen Li

2018 VLSI/CAD Symposium Tutorial (Aug. 7, 20:00-21:00 Room 3F-VII)
2018 VLSI/CAD Symposium Tutorial (Aug. 7, 20:00-21:00 Room 3F-VII)2018 VLSI/CAD Symposium Tutorial (Aug. 7, 20:00-21:00 Room 3F-VII)
2018 VLSI/CAD Symposium Tutorial (Aug. 7, 20:00-21:00 Room 3F-VII)Simen Li
 
全端物聯網探索之旅 - 重點整理版
全端物聯網探索之旅 - 重點整理版全端物聯網探索之旅 - 重點整理版
全端物聯網探索之旅 - 重點整理版Simen Li
 
Node.js Event Loop & EventEmitter
Node.js Event Loop & EventEmitterNode.js Event Loop & EventEmitter
Node.js Event Loop & EventEmitterSimen Li
 
Voltage Controlled Oscillator Design - Short Course at NKFUST, 2013
Voltage Controlled Oscillator Design - Short Course at NKFUST, 2013Voltage Controlled Oscillator Design - Short Course at NKFUST, 2013
Voltage Controlled Oscillator Design - Short Course at NKFUST, 2013Simen Li
 
Phase-locked Loops - Theory and Design
Phase-locked Loops - Theory and DesignPhase-locked Loops - Theory and Design
Phase-locked Loops - Theory and DesignSimen Li
 
Agilent ADS 模擬手冊 [實習3] 壓控振盪器模擬
Agilent ADS 模擬手冊 [實習3] 壓控振盪器模擬Agilent ADS 模擬手冊 [實習3] 壓控振盪器模擬
Agilent ADS 模擬手冊 [實習3] 壓控振盪器模擬Simen Li
 
Agilent ADS 模擬手冊 [實習2] 放大器設計
Agilent ADS 模擬手冊 [實習2]  放大器設計Agilent ADS 模擬手冊 [實習2]  放大器設計
Agilent ADS 模擬手冊 [實習2] 放大器設計Simen Li
 
Agilent ADS 模擬手冊 [實習1] 基本操作與射頻放大器設計
Agilent ADS 模擬手冊 [實習1] 基本操作與射頻放大器設計Agilent ADS 模擬手冊 [實習1] 基本操作與射頻放大器設計
Agilent ADS 模擬手冊 [實習1] 基本操作與射頻放大器設計Simen Li
 
射頻電子實驗手冊 - [實驗8] 低雜訊放大器模擬
射頻電子實驗手冊 - [實驗8] 低雜訊放大器模擬射頻電子實驗手冊 - [實驗8] 低雜訊放大器模擬
射頻電子實驗手冊 - [實驗8] 低雜訊放大器模擬Simen Li
 
射頻電子實驗手冊 - [實驗7] 射頻放大器模擬
射頻電子實驗手冊 - [實驗7] 射頻放大器模擬射頻電子實驗手冊 - [實驗7] 射頻放大器模擬
射頻電子實驗手冊 - [實驗7] 射頻放大器模擬Simen Li
 
射頻電子實驗手冊 [實驗6] 阻抗匹配模擬
射頻電子實驗手冊 [實驗6] 阻抗匹配模擬射頻電子實驗手冊 [實驗6] 阻抗匹配模擬
射頻電子實驗手冊 [實驗6] 阻抗匹配模擬Simen Li
 
射頻電子實驗手冊 [實驗1 ~ 5] ADS入門, 傳輸線模擬, 直流模擬, 暫態模擬, 交流模擬
射頻電子實驗手冊 [實驗1 ~ 5] ADS入門, 傳輸線模擬, 直流模擬, 暫態模擬, 交流模擬射頻電子實驗手冊 [實驗1 ~ 5] ADS入門, 傳輸線模擬, 直流模擬, 暫態模擬, 交流模擬
射頻電子實驗手冊 [實驗1 ~ 5] ADS入門, 傳輸線模擬, 直流模擬, 暫態模擬, 交流模擬Simen Li
 

More from Simen Li (12)

2018 VLSI/CAD Symposium Tutorial (Aug. 7, 20:00-21:00 Room 3F-VII)
2018 VLSI/CAD Symposium Tutorial (Aug. 7, 20:00-21:00 Room 3F-VII)2018 VLSI/CAD Symposium Tutorial (Aug. 7, 20:00-21:00 Room 3F-VII)
2018 VLSI/CAD Symposium Tutorial (Aug. 7, 20:00-21:00 Room 3F-VII)
 
全端物聯網探索之旅 - 重點整理版
全端物聯網探索之旅 - 重點整理版全端物聯網探索之旅 - 重點整理版
全端物聯網探索之旅 - 重點整理版
 
Node.js Event Loop & EventEmitter
Node.js Event Loop & EventEmitterNode.js Event Loop & EventEmitter
Node.js Event Loop & EventEmitter
 
Voltage Controlled Oscillator Design - Short Course at NKFUST, 2013
Voltage Controlled Oscillator Design - Short Course at NKFUST, 2013Voltage Controlled Oscillator Design - Short Course at NKFUST, 2013
Voltage Controlled Oscillator Design - Short Course at NKFUST, 2013
 
Phase-locked Loops - Theory and Design
Phase-locked Loops - Theory and DesignPhase-locked Loops - Theory and Design
Phase-locked Loops - Theory and Design
 
Agilent ADS 模擬手冊 [實習3] 壓控振盪器模擬
Agilent ADS 模擬手冊 [實習3] 壓控振盪器模擬Agilent ADS 模擬手冊 [實習3] 壓控振盪器模擬
Agilent ADS 模擬手冊 [實習3] 壓控振盪器模擬
 
Agilent ADS 模擬手冊 [實習2] 放大器設計
Agilent ADS 模擬手冊 [實習2]  放大器設計Agilent ADS 模擬手冊 [實習2]  放大器設計
Agilent ADS 模擬手冊 [實習2] 放大器設計
 
Agilent ADS 模擬手冊 [實習1] 基本操作與射頻放大器設計
Agilent ADS 模擬手冊 [實習1] 基本操作與射頻放大器設計Agilent ADS 模擬手冊 [實習1] 基本操作與射頻放大器設計
Agilent ADS 模擬手冊 [實習1] 基本操作與射頻放大器設計
 
射頻電子實驗手冊 - [實驗8] 低雜訊放大器模擬
射頻電子實驗手冊 - [實驗8] 低雜訊放大器模擬射頻電子實驗手冊 - [實驗8] 低雜訊放大器模擬
射頻電子實驗手冊 - [實驗8] 低雜訊放大器模擬
 
射頻電子實驗手冊 - [實驗7] 射頻放大器模擬
射頻電子實驗手冊 - [實驗7] 射頻放大器模擬射頻電子實驗手冊 - [實驗7] 射頻放大器模擬
射頻電子實驗手冊 - [實驗7] 射頻放大器模擬
 
射頻電子實驗手冊 [實驗6] 阻抗匹配模擬
射頻電子實驗手冊 [實驗6] 阻抗匹配模擬射頻電子實驗手冊 [實驗6] 阻抗匹配模擬
射頻電子實驗手冊 [實驗6] 阻抗匹配模擬
 
射頻電子實驗手冊 [實驗1 ~ 5] ADS入門, 傳輸線模擬, 直流模擬, 暫態模擬, 交流模擬
射頻電子實驗手冊 [實驗1 ~ 5] ADS入門, 傳輸線模擬, 直流模擬, 暫態模擬, 交流模擬射頻電子實驗手冊 [實驗1 ~ 5] ADS入門, 傳輸線模擬, 直流模擬, 暫態模擬, 交流模擬
射頻電子實驗手冊 [實驗1 ~ 5] ADS入門, 傳輸線模擬, 直流模擬, 暫態模擬, 交流模擬
 

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

  • 1. Chien-Jung Li Sept. 2013 MCS-51 基礎實習 使用IAR Embedded Workbench (I)
  • 3. 燒錄程式的安裝 (I) 1) PC安裝PL2303_Prolific_DriverInstaller_v1210驅動程式。 2) 將燒錄程式「STC-ISP-V488_燒錄程式_免安裝」解壓 縮 到 D 槽 ( 或 C 槽 也 可 ) 。 解 完 後 將 目 錄 裡 的 STC_ISP_V488.exe建立桌面捷徑。 3
  • 4. 燒錄程式的安裝 (II) 3) 安裝AppLocale: papplc.msi (要先改相容性)。裝完後, 再點擊「簡體中文執行_右鍵選單註冊.reg」。 4
  • 6. 64位元win7系統使用STC-ISP程式  在64位元系統要執行ISP時,可能出現以下錯誤:  解法: 1) 到 D:STC-ISP-V488 目 錄 下 將 MSSTDFMT.dll 、 comdlg32.ocx 、 mscomctl.ocx 、 mscomm32.ocx 這 四 支 檔 案 拷 貝 至 C:WindowsSysWOW64目錄下。(若檔案已存在,不要覆蓋) 2) 在C:WindowsSysWOW64目錄下找到cmd.exe,以管理員執行。 接著於終端輸入 regsvr32 mscomm32.ocx regsvr32 comdlg32.ocx 註 冊 完 再 執 行 ISP 程 式 試 試 看 , 如 果 還 不 能 執 行 , 再 註 冊 MSSTDFMT.dll與mscomctl.ocx這兩支檔案。 6
  • 7. 燒錄程式的安裝 (IV) 5) 接上USB (在裝置管理員看一下連接埠號碼) 6) 執行ISP燒錄程式 7) 選擇一支測試映像檔燒錄看看(作法見下頁) 7
  • 9. 安裝8051嵌入式開發環境  目前大多數的MCS-51開發都以Kiel C這套軟體為主  為了能跟以後要開發的SoC晶片銜接,我們改用IAR 這套IDE來進行開發。 9
  • 11. 環境設定 (I) – 選擇裝置 11
  • 12. 環境設定 (II) – 設定Linker 12
  • 13. 環境設定 (III) – 其它 (可不用設定) 13
  • 15. 第一支程式 (II) #include<ioAT89C52.h> void main() { unsigned int a = 0; while(1) { a = 50000; while(a--); a = 50000; while(a--); a = 50000; P1 &= ~(1 << 2); while(a--); a = 50000; while(a--); a = 50000; P1 &= ~(1 << 0); P1 &= ~(1 << 5); P1 &= ~(1 << 6); while(a--); P1 |= (1 << 6); } } 15
  • 18. MCS-51 AT89C52介紹  Compatible with MCS-51™ Products  8K Bytes Flash Memory  Fully Static Operation: 0 Hz to 24 MHz  256 x 8-bit Internal RAM  32 Programmable I/O Lines  Three 16-bit Timer/Counters  8 Interrupt Sources  Programmable Serial Channel  Low-power Idle and Power-down Modes 18
  • 20. Header File /*************************************************************************** * - ioAT89C52.h - * * Special header for the Atmel AT89C52 Microcontroller. ***************************************************************************/ #ifndef IOAT89C52_H #define IOAT89C52_H #define __AT89C52__ #ifdef __IAR_SYSTEMS_ICC__ #ifndef _SYSTEM_BUILD #pragma system_include #endif #pragma language=extended /*------------------------------------------------------------------------- * Power and clock control registers *-------------------------------------------------------------------------*/ __sfr __no_init volatile union { unsigned char PCON; /* Power Control */ struct /* Power Control */ { unsigned char IDL : 1; unsigned char PD : 1; unsigned char GF0 : 1; unsigned char GF1 : 1; unsigned char : 1; unsigned char : 1; unsigned char : 1; unsigned char SMOD : 1; } PCON_bit; } @ 0x87; 20
  • 21. __sfr __no_init volatile unsigned char TH0 @ 0x8C; /* Timer/Counter 0 High Byte */ __sfr __no_init volatile union { unsigned char TCON; /* Timer/Counter Control */ struct /* Timer/Counter Control */ { unsigned char IT0 : 1; unsigned char IE0 : 1; unsigned char IT1 : 1; unsigned char IE1 : 1; unsigned char TR0 : 1; unsigned char TF0 : 1; unsigned char TR1 : 1; unsigned char TF1 : 1; } TCON_bit; } @ 0x88; __sfr __no_init volatile unsigned char TH2 @ 0xCD; /* Timer/Counter 2 High Byte */ __sfr __no_init volatile unsigned char TH1 @ 0x8D; /* Timer/Counter 1 High Byte */ __sfr __no_init volatile union { unsigned char TMOD; /* Timer/Counter Mode Control */ struct /* Timer/Counter Mode Control */ { unsigned char M00 : 1; unsigned char M10 : 1; unsigned char C_T0 : 1; unsigned char GATE0 : 1; unsigned char M01 : 1; unsigned char M11 : 1; unsigned char C_T1 : 1; unsigned char GATE1 : 1; } TMOD_bit; } @ 0x89; 21
  • 22. /*------------------------------------------------------------------------- * I/O port registers *-------------------------------------------------------------------------*/ __sfr __no_init volatile union { unsigned char P1; /* Port 1 */ struct /* Port 1 */ { unsigned char P1_0 : 1; unsigned char P1_1 : 1; unsigned char P1_2 : 1; unsigned char P1_3 : 1; unsigned char P1_4 : 1; unsigned char P1_5 : 1; unsigned char P1_6 : 1; unsigned char P1_7 : 1; } P1_bit; } @ 0x90; __sfr __no_init volatile union { unsigned char P0; /* Port 0 */ struct /* Port 0 */ { unsigned char P0_0 : 1; unsigned char P0_1 : 1; unsigned char P0_2 : 1; unsigned char P0_3 : 1; unsigned char P0_4 : 1; unsigned char P0_5 : 1; unsigned char P0_6 : 1; unsigned char P0_7 : 1; } P0_bit; } @ 0x80; /*--------------------------------------------- * Interrupt system registers *---------------------------------------------*/ __sfr __no_init volatile union { unsigned char IE; /* Interrupt Enable Control */ struct /* Interrupt Enable Control */ { unsigned char EX0 : 1; unsigned char ET0 : 1; unsigned char EX1 : 1; unsigned char ET1 : 1; unsigned char ES : 1; unsigned char ET2 : 1; unsigned char : 1; unsigned char EA : 1; } IE_bit; } @ 0xA8; 22
  • 23. 小程式 #include <ioAT89C52.h> void main(){ // 主程式一定叫main() while(1){ // 嵌入式系統會持續run下去 P1_bit.P1_0 = 0; // 設定port1的第0埠 // 假設該腳是Active Low } } 23
  • 25. 自己定義資料型別關鍵字 25 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;
  • 27. 範例實習1  請打開lab1_Output_LED  練習1: 學習依照header filer指定SFR來使用輸出  練習2: 使用#define來訂別名  練習3, 4: 使用「位元組」操作LED  練習5: 學習移位運算子  練習6: 使用巨集  練習7, 8: 延遲為ms等級的函數 27
  • 28. 練習1:SFR的使用 28 /************************************************************* Filename: exercise1-01.c Description: 學習如何依照header filer對I/O SFR的定義來使用輸出 **************************************************************/ #include<ioAT89C52.h> // 這個header定義了SFR的"名稱"與記憶體位址的對應 // 以後我們就可以直接對SFR的"名稱變數"操作,而不用對"記憶體位址"的內容作操作 void main() { while(1) { P1_bit.P1_0 = 0;// AT89C52開發板輸出 // 是active low, // 輸出為0時, LED點亮 } } // 開發板上的八顆LED {D0, D1, ..., D7}, // 分別對應到 {P1_0, P1_1, ..., P1_7} // 練習1: 點亮D1 // 練習2: 點亮D0, D1, D7 __sfr __no_init volatile union { unsigned char P1; /* Port 1 */ struct /* Port 1 */ { unsigned char P1_0 : 1; unsigned char P1_1 : 1; unsigned char P1_2 : 1; unsigned char P1_3 : 1; unsigned char P1_4 : 1; unsigned char P1_5 : 1; unsigned char P1_6 : 1; unsigned char P1_7 : 1; } P1_bit; } @ 0x90;
  • 29. 練習2:預編譯語法#define的使用 29 /********************************************************************** Filename: exercise1-02.c Description: 使用#define定義port的"別名",用"別名"有時候看起來會更容易理解 ***********************************************************************/ #include<ioAT89C52.h> #define LED0 P1_bit.P1_0 #define LED1 P1_bit.P1_1 #define LED2 P1_bit.P1_2 #define LED3 P1_bit.P1_3 #define LED4 P1_bit.P1_4 #define LED5 P1_bit.P1_5 #define LED6 P1_bit.P1_6 #define LED7 P1_bit.P1_7 void main() { while(1) { LED0 = 0; } } // 練習1: 使用別名點亮D1 // 練習2: 使用別名點亮D0, D1, D7 #define LED0 P1_bit.P1_0 #define LED1 P1_bit.P1_1
  • 30. 練習3:使用位元組設定操作LED 30 /************************************************************ Filename: exercise1-03.c Description: 對位元組"P1"操作來點亮LED0,而不是用單一位元的操作 *************************************************************/ #include<ioAT89C52.h> void main() { while(1) { P1 = 0xFE; // 1111,1110 } } // 開發板上的八顆LED {D0, D1, ..., D7}, // 分別對應到 {P1_0, P1_1, ..., P1_7} // // 練習1: 使用 #define 將P1的別名設定為 LED, // 然後對"LED"別名進行操作同時點亮 // LED0, LED2, LED4 P1_bit.P1_0 = 0; // 位元操作 P1 = 0xFE; // 位元組操作
  • 31. 練習4:使用位元組設定操作LED 31 /******************************************************************************* Filename: exercise1-04.c Description: 操作位元組"P1"點亮D2,延時一段時間後,"再"點亮D0, D5, D6 (D2不可熄滅) *******************************************************************************/ #include<ioAT89C52.h> void main() { unsigned int a = 0; // 在IAR/Kiel中, int的型別是16位元, unsigned int範圍為0~65535 while(1) { a = 50000; P1 = 0xFB; // 1111,1011 點亮D2 while(a--); a = 50000; P1 = 0x9A; // 1001,1010 點亮D0, D5, D6, 但D2也維持點亮 while(a--); while(1); // 將此行註解掉, LED會開始閃爍 // while(1)不可亂用, 因程式會在此卡死, 這裡只是demo } } // 練習1: 對"位元組"使用"位元操作"運算, 將第16行更改為 // P1 &= ~(0x61); // 0110,0001 // 想想看, 這是甚麼原理? // 練習2: 點亮D0, D2, D5, D6之後,延遲一段時間,熄滅D6。將18行改為 // a = 50000; // P1 |= 0x40; // 0100,0000 // while(a--); // 想想看, 這是甚麼原理? // 當我們要對"位元組"內的某個、或某幾個bits做設定,但又不影響其他bits原有的狀態時, // 位元操作運算 &= 與 |= 是非常實用而且常見的運算手法喔! P1 &= ~(0x61) // 位元操作, 設為0 P1 |= 0x40 // 位元操作, 設為1
  • 32. /**************************************************************************************** Filename: exercise1-05.c Description: 學會使用移位操作,設定"P1"點亮D2,延時一段時間後,"再"點亮D0, D5, D6 (D2不可熄滅) 再延遲一段時間後,關閉熄滅D6 *****************************************************************************************/ #include<ioAT89C52.h> void main() { unsigned int a = 0; while(1) { a = 50000; while(a--); a = 50000; while(a--); a = 50000; P1 &= ~(1 << 2); // 將1左移2位再取~ 得到 1111,1011 點亮D2 while(a--); a = 50000; while(a--); a = 50000; P1 &= ~(1 << 0); // 0000,0001 -> 1111,1110 點亮D0 P1 &= ~(1 << 5); // 0010,0000 -> 1101,1111 點亮D5 P1 &= ~(1 << 6); // 0100,0000 -> 1011,1111 點亮D6 while(a--); P1 |= (1 << 6); // 0100,0000 熄滅D6 } } 練習5:學習移位運算子 32 P1 &= ~(1<<2); // 位元操作, 設為0 P1 |= (1<<2); // 位元操作, 設為1
  • 33. /************************************************************************************************** Filename: exercise1-06.c Description: 學會使用巨集(macro)以簡化程式碼的寫法, 重新改寫exercise1-05.c **************************************************************************************************/ #include<ioAT89C52.h> #define BV(n) (1 << (n)) // 這是向左移位操作的macro void main() { unsigned int a = 0; while(1) { a = 50000; while(a--); a = 50000; while(a--); a = 50000; P1 &= ~BV(2); // 將1左移2位再取~ 得到 1111,1011 點亮D2 while(a--); a = 50000; while(a--); a = 50000; P1 &= ~BV(0); // 0000,0001 -> 1111,1110 點亮D0 P1 &= ~BV(5); // 0010,0000 -> 1101,1111 點亮D5 P1 &= ~BV(6); // 0100,0000 -> 1011,1111 點亮D6 while(a--); P1 |= BV(6); // 0100,0000 熄滅D6 } } 練習6:使用巨集(Macro) 33 #define BV(n) (1 << (n))
  • 34. /************************************************************************* Filename: exercise1-07.c Description: 將延時放的更長 ***************************************************************************/ #include<ioAT89C52.h> #define BV(n) (1 << (n)) // 這是向左移位操作的macro typedef signed char int8; // 以後8位元的有號數就可以用int8做宣告 typedef unsigned char uint8; // 以後8位元的無號數就可以用uint8做宣告 void delay(uint8); // delay函數的宣告 void main() { while(1) { P1 &= ~BV(2); // 將1左移2位再取~ 得到 1111,1011 點亮D2 delay(255); delay(255); P1 &= ~BV(0); // 0000,0001 -> 1111,1110 點亮D0 P1 &= ~BV(5); // 0010,0000 -> 1101,1111 點亮D5 P1 &= ~BV(6); // 0100,0000 -> 1011,1111 點亮D6 delay(255); P1 |= BV(6); // 0100,0000 熄滅D6 delay(150); } } void delay(uint8 d) // delay函數的定義, 也就是這個函數要執行的動作 { uint8 x,y; for(x=d;x>0;x--) for(y=255;y>0;y--); } // 使用雙for迴圈來延長時間, 最高可延長 256*256 = 65536 (65535遞減至0) // 在這個練習裡, 你也學到函數的宣告與定義 // 練習: 試著改變延時的長度 練習7:延時函式 34 unsigned int a = 0; a = 50000; while(a--);
  • 35. 練習8:毫秒(ms)等級的延時函式 35 /************************************************************************ Filename: exercise1-08.c Description: 1ms延遲函數, 將延時放的更長 *************************************************************************/ #include<ioAT89C52.h> #define BV(n) (1 << (n)) // 這是向左移位操作的macro typedef signed char int8; // 以後8位元的有號數就可以用int8做宣告 typedef unsigned char uint8; // 以後8位元的無號數就可以用uint8做宣告 void delayms(uint8); // delay函數的宣告 void main() { while(1) { P1 &= ~BV(0); // 點亮D0 delayms(255); delayms(245); P1 |= BV(0); // 熄滅D0 delayms(255); delayms(245); } } void delayms(uint8 time) { uint8 n; while(time>0) { n = 162; while(n>0) n--; time --; } }
  • 36. 小錦囊 (I) 36 #define LED0 P1_bit.P1_0 P1 &= ~(1 << 0); // 0000,0001 -> 1111,1110 P1 |= (1 << 6); // 0100,0000 #define BV(n) (1 << (n)) // 這是向左移位操作的macro P1 &= ~BV(5); // 0010,0000 -> 1101,1111 P1 |= BV(6); // 0100,0000 typedef signed char int8; typedef unsigned char uint8;
  • 37. 小錦囊 (II) 37 void delayms(uint8 time) { uint8 n; while(time>0) { n = 162; while(n>0) n--; time --; } }
  • 39. LED0的驅動程式(I) 39  為方便說明,我們僅以單一顆LED0的閃爍為例: /********************************************************************* Filename: exercise1-09.c Description: 以函式包裝對LED0的操作(最簡單的驅動程式) *********************************************************************/ #include<ioAT89C52.h> #define LED0 P1_bit.P1_0 typedef unsigned char uint8; /* Declare Function Prototype */ void drv_LED0_Init(void); void drv_LED0_Toggle(void); void delayms(uint8); void main(void) { drv_LED0_Init(); while(1) { drv_LED0_Toggle(); // Change LED state delayms(250); // Delay for 250 ms delayms(250); // Delay for 250 ms, 1 Hz Flash = 0.5s On + 0.5s OFF } }
  • 40. LED0的驅動程式(II) 40 /*********************************************************************** * @fn drv_LED0_Init * @brief Initialize LED0 State * @param None * @return None **********************************************************************/ void drv_LED0_Init(void) { LED0 = 1; // 初始時LED0熄滅 } /*********************************************************************** * @fn drv_LED0_Toggle * @brief Changes LED0 State * @param None * @return None **********************************************************************/ void drv_LED0_Toggle(void) { // Change the LED from OFF to ON (or vice versa) LED0 = ~LED0; }
  • 41. LED0的驅動程式(III) 41 /********************************************************************** * @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 --; } } /********************************************************************* **********************************************************************/
  • 42. /************************************ * @fn drv_LED0_Off * @brief Turn Off LED0 * @param None * @return None ************************************/ void drv_LED0_Off(void) { LED0 = 1; } 用On/Off函式並使用全域變數(I) 42  將exercise1-09.c另存為exercise1-10.c,並加入: uint8 gLED0_state; // 'g' notice us it's a global var. void drv_LED0_Init(void); void drv_LED0_On(void); void drv_LED0_Off(void); void drv_LED0_Toggle(void); void delayms(uint8); /************************************ * @fn drv_LED0_On * @brief Turn On LED0 * @param None * @return None ************************************/ void drv_LED0_On(void) { LED0 = 0; }
  • 43. 用On/Off函式並使用全域變數(II) 43 /*************************************************************** * @fn drv_LED0_Toggle * @brief Changes LED0 State * @param None * @return None **************************************************************/ void drv_LED0_Toggle(void) { // Change the LED from OFF to ON (or vice versa) if (gLED0_state == 1) { gLED0_state = 0; drv_LED0_Off(); } else { gLED0_state = 1; drv_LED0_On(); } }
  • 46. 範例實習2  請打開lab2_Input_Button  練習1: 使用輸入 (持續按下時LED點亮)  練習2: 使用輸入 (按一下button即可開關LED)  練習3: 簡易軟體debounce  練習4: 以函式包裝檢測按鍵是否被按下的功能 46
  • 47. 練習1:持續按下時LED點亮 47 /********************************************************************************** Filename: exercise2-01.c Description: 使用button (這個程式還未使用中斷) ***********************************************************************************/ #include<ioAT89C52.h> #define LED0 P1_bit.P1_0 #define BTN1 P3_bit.P3_2 void main() { BTN1 = 1; // I/O要當輸入時,要先寫入1 while(1) { if (BTN1 == 0){ LED0 = 0; }else{ LED0 = 1; } } } // 程式效果: 按鍵按下(持續按下), LED0維持點亮, 只要一放開就熄滅. // 開發板上的4個獨立按鍵 {INT0, INT1, T0, T1}, 分別對應到 {P3_2, P3_3, P3_4, P3_5} // 練習1: 試著使用其他按鍵 // 練習2: 試著做出一個 #define LED0 P1_bit.P1_0 #define BTN1 P3_bit.P3_2
  • 48. 練習2:按一下按鈕就改變LED 48 /**************************************************************************************** Filename: exercise2-02.c Description: 使用button (這個程式還未使用中斷) ****************************************************************************************/ #include<ioAT89C52.h> #define LED0 P1_bit.P1_0 #define BTN1 P3_bit.P3_2 // 這裡使用全域變數, 當旗標使用, 初始值為0 volatile unsigned char btn_flag = 0; void main() { BTN1 = 1; // I/O要當輸入時,要先寫入1 while(1) { if (BTN1 == 0) btn_flag = ~btn_flag; // 當btn按下, 所有位元反向 if (btn_flag != 0) LED0 = 0; // 若btn_flag不為0, 就點亮LED0 else LED0 = 1; // 反之btn_flag若為0, 就熄滅LED0 } } // 燒錄完後,試試看, 有沒有發現甚麼很詭異的現象? volatile unsigned char btn_flag = 0;
  • 50. 小錦囊:軟體Debounce小程式 50 if (BTN1 == 0) { delayms(50); if (BTN1 == 0){ while(BTN1 == 0); btn_flag = ~btn_flag; } }
  • 51. 練習3:去抖動 51 /*********************************************************************************** Filename: exercise2-03.c Description: 使用button / Simple Debounce (這個程式還未使用中斷) ************************************************************************************/ #include<ioAT89C52.h> #define LED0 P1_bit.P1_0 #define BTN1 P3_bit.P3_2 typedef unsigned char uint8; volatile unsigned char btn_flag = 0; void delayms(uint8); void main() { BTN1 = 1; // I/O要當輸入時,要先寫入1 while(1) { if (BTN1 == 0) { delayms(50); if (BTN1 == 0){ // 這裡好像少了甚麼 btn_flag = ~btn_flag; } } if ((btn_flag & 0x01) == 1) LED0 = 0; else LED0 = 1; } } void delayms(uint8 time) { uint8 n; while(time>0) { n = 162; while(n>0) n--; time --; } }
  • 52. 練習4:以函式包裝對硬體的操作 52 /********************************************************************** Filename: exercise2-04.c Description: 使用button / Simple Debounce (這個程式還未使用中斷) ***********************************************************************/ #include<ioAT89C52.h> #define LED0 P1_bit.P1_0 #define BTN1 P3_bit.P3_2 #define BTN_NOT_PRESSED 0 #define BTN_PRESSED 1 #define LED_ON 0 #define LED_OFF 1 typedef unsigned char uint8; volatile unsigned char btn_flag = 0; void BTN_Init(void); uint8 BTN_Get_Input(uint8 debounce_time); void delayms(uint8); void main() { BTN_Init(); while(1) { if( BTN_Get_Input(50) ){ btn_flag = ~btn_flag; } LED0 = (btn_flag?LED_ON:LED_OFF); } } void BTN_Init(void) { BTN1 = 1; // I/O要當輸入時,要先寫入1 } uint8 BTN_Get_Input(uint8 debounce_time) { uint8 BTN_val = BTN_NOT_PRESSED; if (BTN1 == 0) { delayms(debounce_time); if (BTN1 == 0) { while(BTN1==0); BTN_val = BTN_PRESSED; } } return BTN_val; // Return BTN value } void delayms(uint8 time) { 略 }
  • 54. 符號 0 1 2 3 4 5 編碼 0x3F 0x06 0x5B 0x4F 0x66 0x6D 符號 6 7 8 9 A B 編碼 0x7D 0x07 0x7F 0x6F 0x77 0x7C 符號 C D E F 無顯示 編碼 0x39 0x5E 0x79 0x71 0x00 七段顯示器 54 0 1 2 3 4 5 6 7
  • 57. 範例實習3  請打開lab3_7seg_keypad  練習1:靜態顯示一位 (練習: 用按鍵改變顯示位)  練習2:靜態顯示多位,並隨時間流逝遞增符號 (練習:改用按鍵改變顯示符號)  練習3:使用動態掃描同時顯示多位7段顯示器  練習4:掃描式矩陣鍵盤 57
  • 58. 練習1:點亮一顆七段顯示器 58 /********************************************************************* Filename: exercise3-01.c Description: 點亮一顆7段顯示器 *********************************************************************/ #include<ioAT89C52.h> #define seg_set P2_bit.P2_6 #define pos_set P2_bit.P2_7 #define SEG7LED P0 #define POS7LED P0 void main() { pos_set = 1; POS7LED = 0xFE; // 1111,1110 pos_set = 0; seg_set = 1; SEG7LED = 0x71; // 0111,0001 seg_set = 0; while(1); } // 練習: 按下按鍵, 依序點亮其他的7段顯示器
  • 59. 練習2:點亮多顆顯示器(I) 59 /******************************************************************* Filename: exercise3-02.c Description: 依序顯示符號0, 1,2,3, ->, A, b, C, d, E, F ********************************************************************/ #include<ioAT89C52.h> #define seg_set P2_bit.P2_6 #define pos_set P2_bit.P2_7 #define SEG7LED P0 #define POS7LED P0 typedef unsigned char uint8; void DispScrClr(void); void DispShowPos(uint8 pos); void DispShowSym(uint8 sym_num, uint8 dp); void delayms(uint8 time); // 符號表 0,1,2,...,9, A, b, C, d, E, F uint8 symbols[]={ 0x3F,0x06,0x5B,0x4F, 0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C, 0x39,0x5E,0x79,0x71}; void main() { DispScrClr(); uint8 symbol_num; while(1) { DispShowPos(0xF0); // 1111, 0000 (pos0~3) for(symbol_num=0;symbol_num<16;symbol_num++) { if (symbol_num>5){ DispShowPos(0xE0); // 1110, 0000 DispShowSym(symbol_num, 1); }else{ DispShowSym(symbol_num, 0); } delayms(255); } DispScrClr(); delayms(255); } }
  • 60. 練習2:點亮多顆顯示器(II) /************************************************************************** * @fn DispScrClr * @brief Clear the Display Screen. Clear all 7-Seg LEDs into blank * @param None * @return None *************************************************************************/ void DispScrClr(void) { SEG7LED = 0x00; seg_set = 1; seg_set = 0; POS7LED = 0xFF; pos_set = 1; pos_set = 0; } /************************************************************************* * @fn DispShowPos * @brief Show the Display Screen with assigned positions. * @param None * @return None ************************************************************************/ void DispShowPos(uint8 pos) { POS7LED = ~pos; pos_set = 1; pos_set = 0; } /********************************************************* * @fn DispShowSym * @brief Show the Symbol with dot-point(dp) or not ********************************************************/ void DispShowSym(uint8 sym_num, uint8 dp) { uint8 sym; if(dp!=0) sym = symbols[sym_num]|0x80; else sym = symbols[sym_num]; SEG7LED = sym; seg_set = 1; seg_set = 0; } /******************************************************** * @fn delayms * @brief delay with ms ********************************************************/ void delayms(uint8 time) { uint8 n; while(time>0) { n = 162; while(n>0) n--; time --; } } 60
  • 63. 練習3:各位依序顯示數字0-7 #define POS(n) (1 << (n)) void DispSym_at_Pos(uint8 pos, uint8 symbol_num, uint8 dp); /*************************************************************************** * @fn DispSym_at_Pos * @brief Show the Symbol at specific position with dot-point(dp) or not * @param None * @return None ***************************************************************************/ void DispSym_at_Pos(uint8 pos, uint8 symbol_num, uint8 dp) { DispShowSym(symbol_num, dp); DispShowPos(pos); } void main() { DispScrClr(); uint8 symbol_num = 0; uint8 pos_num = 0; while(1) { for (pos_num=0;pos_num<8;pos_num++){ DispSym_at_Pos(POS(pos_num),symbol_num,0); symbol_num++; if (symbol_num ==8) symbol_num=0; delayms(250); } } } 63
  • 65. 鍵盤鍵值對應 65 key_val keycode_bin keycode_hex 無 1111,0000 0xF0 0 0111,1110 0x7E 1 0111,1101 0x7D 2 0111,1011 0x7B 3 0111,0111 0x77 4 1011,1110 0xBE 5 1011,1101 0xBD 6 1011,1011 0xBB 7 1011,0111 0xB7 8 1101,1110 0xDE 9 1101,1101 0xDD 10 1101,1011 0xDB 11 1101,0111 0xD7 12 1110,1110 0xEE 13 1110,1101 0xED 14 1110,1011 0xEB 15 1110,0111 0xE7 0 4 8 C 1 5 9 D 2 6 A E 3 7 B F P3.0 P3.1 P3.2 P3.3 P3.7 P3.6 P3.5 P3.4 0 4 8 C 1 5 9 D 2 6 A E 3 7 B F P3.0 P3.1 P3.2 P3.3 P3.7 P3.6 P3.5 P3.4
  • 66. 練習4:將按下掃描鍵盤值顯示出來 66 /********************************************************* Filename: exercise3-04.c Description: keypad scan *********************************************************/ #include<ioAT89C52.h> #define seg_set P2_bit.P2_6 #define pos_set P2_bit.P2_7 #define KeyPort P3 typedef unsigned char uint8; uint8 KeypadScan(void); uint8 KeyPushed(uint8 keycode); volatile uint8 n; void delayms(uint8 time); uint8 symbols[]={ 0x3F,0x06,0x5B,0x4F, 0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C, 0x39,0x5E,0x79,0x71}; void main() { // use POS4 of 7-seg LED to show the pushed key number P0=0xEF; pos_set=1; pos_set=0; while(1) { KeyPort = 0xF0; // H4-1(input), L4-0(output) if(KeyPort!=0xF0) { delayms(25); n = KeyPushed(KeypadScan()); } if(n!=0xFF) { P0=symbols[n]; seg_set=1; seg_set=0; }else{ P0=0x00; seg_set=1; seg_set=0; } } }
  • 67. uint8 KeypadScan(void) { uint8 key_code; KeyPort = 0xFE; // 1111,1110: check col_1 if(KeyPort != 0xFE) { key_code = (KeyPort & 0xF0)|0x0E; delayms(1); return key_code; } KeyPort = 0xFD; // 1111,1101: check col_2 if(KeyPort != 0xFD) { key_code = (KeyPort & 0xF0)|0x0D; delayms(1); return key_code; } KeyPort = 0xFB; // 1111, 1011: check col_3 if(KeyPort != 0xFB) { key_code = (KeyPort & 0xF0)|0x0B; delayms(1); return key_code; } KeyPort = 0xF7; // 1111, 0111: check col_4 if(KeyPort != 0xF7) { key_code = (KeyPort & 0xF0)|0x07; delayms(1); return key_code; } return 0xFF; } uint8 KeyPushed(uint8 keycode) { switch(keycode) { case 0x7E: return 0; break; case 0x7D: return 1; break; case 0x7B: return 2; break; case 0x77: return 3; break; case 0xBE: return 4; break; case 0xBD: return 5; break; case 0xBB: return 6; break; case 0xB7: return 7; break; case 0xDE: return 8; break; case 0xDD: return 9; break; case 0xDB: return 10; break; case 0xD7: return 11; break; case 0xEE: return 12; break; case 0xED: return 13; break; case 0xEB: return 14; break; case 0xE7: return 15; break; default: return 0xFF; break; } } void delayms(uint8 time) { uint8 n; while(time>0) { n = 162; while(n>0) n--; time --; } } 67
  • 69. 1602A LCM模組 RS R/W 作用 0 0 將指令碼寫入IR(指令暫存器),並執行指令。 0 1 讀取BF(DB7)與位址計數器AC(DB0~6)內容。 1 0 將資料寫入DR(資料暫存器)。 LCM內部自動執行DR->DD RAM或DR->CG RAM。 1 1 讀取DR之資料。 LCM內部自動執行DD RAM->或CG RAM->DR。 69 MC U
  • 70. 字元圖形顯示到螢幕的過程 70 ‘I’, ‘ ’, ‘a’, ‘m’, … (ASCII) 文字擺放的 起始位置 I a m a t e a c h e 只要指定起始位置,每個字元寫入 後,AC就會自動累加(減),因此所 有字元就會依序顯示出來。
  • 72. CG RAM (自製字元圖形) 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}; /********************************************************** * @fn LCD_DefChar * @brief This function help you define your own pattern * @param uint8 id: offset of the CGRAM, uint8 *pat points * to the pattern table (array). * @return None ***********************************************************/ void LCD_DefChar(uint8 id, uint8 *pat) { uint8 i; LCD_CmdWr(0x40 + ( id<<3 )); // Set address of CGRAM for(i=0;i<8;i++){ LCD_DataWr(*pat++); } } 72
  • 73. LCM共有11種指令 73 指令 動作 RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 執行 時間 功能設定 0 0 0 0 1 DL(1) N(2) F(3) X X 40 us 清除顯示器 0 0 0 0 0 0 0 0 0 1 1.64ms 游標回左上角 0 0 0 0 0 0 0 0 1 X 40 us 設定輸入模式 0 0 0 0 0 0 0 1 I/D(4) S(4) 40 us 螢幕開或關 0 0 0 0 0 0 1 D C B 40 us 游標/顯示移位 0 0 0 0 0 1 S/C(5) R/L(5) X X 40 us 設定CGRAM地址 0 0 0 1 A A A A A A 40 us 設定DDRAM地址 0 0 1 A A A A A A A 40 us 讀取BF與地址 0 1 BF(6) A A A A A A A 40 us 寫資料至RAM 1 0 D D D D D D D D 40 us 從RAM讀資料 1 1 D D D D D D D D 40 us
  • 74. 日立HD44780相容LCD之常用指令表 74 No. Instruction Hex Decimal 1 Function Set: 8-bit, 1 Line, 5x7 Dots 0x30 48 2 Function Set: 8-bit, 2 Line, 5x7 Dots 0x38 56 3 Function Set: 4-bit, 1 Line, 5x7 Dots 0x20 32 4 Function Set: 4-bit, 2 Line, 5x7 Dots 0x28 40 5 Entry Mode 0x06 6 6 Display off Cursor off (clearing display without clearing DDRAM content) 0x08 8 7 Display on Cursor on 0x0E 14 8 Display on Cursor off 0x0C 12 9 Display on Cursor blinking 0x0F 15 10 Shift entire display left 0x18 24 12 Shift entire display right 0x1C 30 13 Move cursor left by one character 0x10 16 14 Move cursor right by one character 0x14 20 15 Clear Display (also clear DDRAM content) 0x01 1 16 Set DDRAM address or cursor position on display 0x80+add 128+add 17 Set CGRAM address or set pointer to CGRAM location 0x40+add 64+add
  • 78. 練習1:撰寫LCM驅動程式 78 #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 /* HD44780 Commands */ #define LCD_CMD_CLS 0x01 #define LCD_CMD_FNCT 0x38 // 16*2 display, 5*7 bitmap, 8-bits data port #define LCD_CMD_MODE 0x06 // after R/W one char, addr+1, cursor+1 #define LCD_CMD_ON_OFF 0x0C // Enable LCD, Cursor OFF, No Blink Cursor typedef unsigned char uint8;
  • 79. 79 static uint8 LCD_MaxCols; static uint8 LCD_MaxRows; 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}; char StrL1[]="LCD 1602 Test"; char StrL2[]="OK"; static void LCD_CursorSet(uint8 row, uint8 col); void LCD_DataWr(uint8 data); void LCD_CmdWr(uint8 cmd); void LCD_Init(uint8 maxrows, uint8 maxcols); void LCD_DispChar(uint8 row, uint8 col, char c); void LCD_DispStr(uint8 row, uint8 col, char *s); void LCD_ClrLine(uint8 line); void LCD_ClrScr(void); void LCD_DefChar(uint8 id, uint8 *pat); void LCD_DispHorBarInit(void); void LCD_DispHorBar(uint8 row, uint8 col, uint8 val); void delayms(uint8 time);
  • 80. 80 /********************************************************************************** * @fn LCD_Init * @brief LCD Initilization * @param uint8 maxrows: max number of rows, uint8 maxcols: max number of columns * @return None **********************************************************************************/ void LCD_Init(uint8 maxrows, uint8 maxcols) { LCD_MaxCols = maxcols; LCD_MaxRows = maxrows; delayms(30); LCD_EN = 0; LCD_RS = 0; LCD_RW = 0; 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_ON_OFF); LCD_CmdWr(LCD_CMD_MODE); LCD_CmdWr(LCD_CMD_CLS); delayms(2); } /***************************************** * @fn LCD_CmdWr * @brief Write a command to the LCD * @param uint8 cmd: the command * @return None *****************************************/ void LCD_CmdWr(uint8 cmd) { delayms(1); LCD_RS = LCD_SEL_CMD; LCD_RW = LCD_IO_WRITE; LCD_DATA_PORT = cmd; delayms(1); LCD_EN = 1; delayms(1); LCD_EN = 0; }
  • 81. 81 /******************************************************************************************* * @fn LCD_ClrLine * @brief Clear a certain line * @param uint8 line: 1 is the first line, and 2 is the second line * @return None ******************************************************************************************/ void LCD_ClrLine(uint8 line) { uint8 i; if(line < LCD_MaxRows) { LCD_CursorSet(line, 0); for(i=0;i<LCD_MaxCols;i++){ LCD_DataWr(' '); } LCD_CursorSet(line, 0); } } /************************************ * @fn LCD_ClrScr * @brief Clear whole screen * @param None * @return None ***********************************/ void LCD_ClrScr(void) { LCD_CmdWr(LCD_CMD_CLS); } /*********************************************** * @fn LCD_DataWr * @brief Write a data to the LCD * @param uint8 data: the data * @return None **********************************************/ void LCD_DataWr(uint8 data) { delayms(1); LCD_RS = LCD_SEL_DATA; LCD_RW = LCD_IO_WRITE; LCD_DATA_PORT = data; delayms(1); LCD_EN = 1; delayms(1); LCD_EN = 0; }
  • 82. 82 /*********************************************************************************** * @fn LCD_CursorSet * @brief Set the position of the cursor * @param (uint8 row, uint8 col) sets the position * @return None **********************************************************************************/ static void LCD_CursorSet(uint8 row, uint8 col) { switch(row){ case 0: if(LCD_MaxRows==1){ if (col < (LCD_MaxCols >> 1)) // If used only one line LCD LCD_CmdWr(0x80 + col); // First half of line starts at 0x80 else // Second half of line starts at 0xC0 LCD_CmdWr(0xC0 + col - (LCD_MaxCols >> 1)); }else{ LCD_CmdWr(0x80 + col); // select line 1 } break; case 1: LCD_CmdWr(0xC0 + col); // select line 2 break; case 2: LCD_CmdWr(0x80 + LCD_MaxCols + col); // select line 3 break; case 3: LCD_CmdWr(0xC0 + LCD_MaxCols + col); // select line 4 break; } }
  • 83. 83 /************************************************************************************* * @fn LCD_DispChar * @brief Show a character at specific postion * @param (uint8 row, uint8 col) is the postion, and char c: the character to show * @return None ************************************************************************************/ void LCD_DispChar(uint8 row, uint8 col, char c) { if(row < LCD_MaxRows && col < LCD_MaxCols) { LCD_CursorSet(row, col); LCD_DataWr(c); } } /*********************************************************************************** * @fn LCD_DispStr * @brief Display a string from a specific position * @param (uint8 row, uint8 col) sets the position and char *s is the string * @return None *********************************************************************************/ void LCD_DispStr(uint8 row, uint8 col, char *s) { uint8 i; if(row < LCD_MaxRows && col < LCD_MaxCols){ LCD_CursorSet(row, col); i = col; while( i < LCD_MaxCols && *s){ LCD_DataWr(*s++); i++; } } }
  • 84. /*************************************************************************************************** * @fn LCD_DispHorBar * @brief Display the horizon bar * @param (uint8 row, uint8 col) sets the position, uint8 val sets the value of full (100%) * @return None ***************************************************************************************************/ void LCD_DispHorBar(uint8 row, uint8 col, uint8 val) { uint8 i, full, frac; full = val/5; // how many full blocks to turn on frac = val%5; // portion of block if(row < LCD_MaxRows && (col + full -1) < LCD_MaxCols){ i = 0; LCD_CursorSet(row, col); while(full > 0) { LCD_DataWr(5); // Send Custom character #5, which is full block i++; full--; } if(frac>0){ LCD_DataWr(frac); // custom char #frac } } } /************************************** * @fn LCD_DispHorBarInit * @brief HorizonBar Initilize * @param None * @return None *************************************/ void LCD_DispHorBarInit(void) { LCD_DefChar(1, &LCD_DispBar1[0]); LCD_DefChar(2, &LCD_DispBar2[0]); LCD_DefChar(3, &LCD_DispBar3[0]); LCD_DefChar(4, &LCD_DispBar4[0]); LCD_DefChar(5, &LCD_DispBar5[0]); } 84
  • 85. 85 /********************************************************** * @fn LCD_DefChar * @brief This function help you define your own pattern * @param uint8 id: offset of the CGRAM, uint8 *pat points * to the pattern table (array). * @return None ***********************************************************/ void LCD_DefChar(uint8 id, uint8 *pat) { uint8 i; LCD_CmdWr(0x40 + ( id<<3 )); // Set address of CGRAM for(i=0;i<8;i++){ LCD_DataWr(*pat++); } } /******************************************************** * @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 --; } }
  • 86. 86 void main() { LCD_Init(2, 16); LCD_DispStr(0,0,StrL1); LCD_DispStr(1,0,StrL2); BTN1 = 1; BTN2 = 1; while(1) { if (BTN1 == 0) { delayms(50); if (BTN1 == 0) { while(BTN1 == 0); LCD_ClrScr(); } LCD_DispStr(0,0,StrL1); } if (BTN2 == 0) { delayms(50); if (BTN2 == 0) { while(BTN2 == 0); LCD_ClrScr(); LCD_DispStr(1,0,"ROW1, COL0"); LCD_DispStr(0,1,"ROW0, COL1"); } } } }
  • 87. 練習2:動態效果 87 void main() { uint8 i = 0, j; BTN1 = 1; char *str1 = "Dynamic Show"; char *str2 = "rolling text"; LCD_Init(2, 16); LCD_DispStr(0, 0, StrL1); for(j=0;j<3;j++) { delayms(250); } LCD_DispStr(1, 0, StrL2); for(j=0;j<8;j++) { delayms(250); } LCD_ClrScr(); delayms(2); LCD_DispStr(0, 0, str1); for(j=0;j<16;j++) { LCD_CmdWr(0x1C); delayms(250); } for(j=0;j<16;j++) { LCD_CmdWr(0x18); delayms(250); } delayms(250); while(1) { if (BTN1 == 0) { delayms(50); if (BTN1 == 0) { while(BTN1 == 0); LCD_ClrLine(0); while(*(str2+i)) { LCD_DispChar(0, i, *(str2+i)); i++; delayms(200); } i=0; } } } }
  • 88. 練習3:進度條製作 88 void main() { uint8 i, percent_bar; char num[4]; BTN1 = 1; char *str1 = "Dynamic Show"; LCD_Init(2, 16); LCD_DispHorBarInit(); LCD_DispStr(0, 0, str1); while(1) { if (BTN1 == 0) { delayms(50); if (BTN1 == 0) { while(BTN1 == 0); 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); } } } } }
  • 91. 中斷的優缺點  優點: 1) 解決快速主機與慢速I/O設備的資料傳送問題。 2) CPU可分時為多個I/O設備服務,提高電腦利用率。 3) 即時性。 4) 可處理設備故障及掉電等突發事件,使系統可靠性提高。  缺點: 1) ISR程式不可執行太久 2) 不可於ISR中呼叫太多函式 3) 有critical section的問題 4) 不能呼叫不可重進入函式 5) 巢狀中斷可能使堆疊溢位 91
  • 92. C51中斷結構:暫存器IE/TCON/IP EX0 EA PX0 0 1 ET0 PT0 0 1 EX1 PX1 0 1 ET1 PT1 0 1 ES PS 0 1 ≥1 RI TI SCON TCON IE0 TF0 IE1 TF1 10 1 0 1 IT0 IT1 INT0 INT1 T0 T1 RX TX IE IP 1 11 1 1 1 1 1 0 92
  • 93. 中斷入口 /* Interrupt Vectors */ #define extern0 0x03 /* External interrupt 0 */ #define IE0_int 0x03 /* External interrupt 0 */ #define timer0 0x0B /* Timer 0 Interrupt */ #define TF0_int 0x0B /* Timer 0 Interrupt */ #define extern1 0x13 /* External interrupt 1 */ #define IE1_int 0x13 /* External interrupt 1 */ #define timer1 0x1B /* Timer 1 Interrupt */ #define TF1_int 0x1B /* Timer 1 Interrupt */ ... 中斷源 中斷旗標 ISR入口 優先權 外部中斷0 IE0 0x0003 高 定時/計數器0 (T0) TF0 0x000B 外部中斷1 IE1 0x0013 定時/計數器0 (T1) TF1 0x001B 串列埠 RI或TI 0x0023 低 93
  • 94. 範例實習5  請打開lab5_Interrupt  練習1: 外部中斷0  練習2: 觀察中斷打斷目前工作  練習3: 優先權的設置  練習4: 在ISR中更改全域變數的問題  練習5: 在ISR中使用不可重進入函式的問題 94
  • 95. 練習1:使用外部中斷0 95 /************************************************************************************ Filename: exercise5-01.c Description: 使用button引發中斷, 按壓BTN1以點亮或熄滅LED0 開發板按鍵{INT0, INT1, T0, T1}, 分別對應到 {P3_2, P3_3, P3_4, P3_5} *************************************************************************************/ #include<ioAT89C52.h> #define LED0 P1_bit.P1_0 #define BTN1 P3_bit.P3_2 typedef unsigned char uint8; void delayms(uint8); void main() { BTN1 = 1; // I/O要當輸入時,要先寫入1 LED0 = 1; TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標設為0 IE_bit.EX0 = 1; // 外部中斷0致能 IE_bit.EA = 1; // 總中斷致能 while(1) { ; } } void delayms(uint8 time) { uint8 n; while(time>0) { n = 162; while(n>0) n--; time --; } } /* Symbol defined in I/O header file */ #pragma vector = extern0 __interrupt void Int_Extern0(void) { LED0 = ~LED0; TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標清為0 } // 如果按壓按鈕的效果不好, 請加入debounce程式 // 練習: 改以外部中斷1實作
  • 96. 練習2:中斷會打斷當前工作 96  平時LED1閃爍,按BTN1發生中斷使LED0閃爍10次 #include<ioAT89C52.h> #define LED0 P1_bit.P1_0 #define LED1 P1_bit.P1_1 #define BTN1 P3_bit.P3_2 typedef unsigned char uint8; void delayms(uint8); void main() { BTN1 = 1; // I/O要當輸入時,要先寫入1 LED0 = 1; LED1 = 1; TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標設為0 IE_bit.EX0 = 1; // 外部中斷0致能 IE_bit.EA = 1; // 總中斷致能 while(1) { delayms(250); delayms(250); LED1 = ~LED1; } } #pragma vector = extern0 __interrupt void Int_Extern0(void) { uint8 i; for(i=0;i<20;i++){ LED0 = ~LED0; delayms(250); } TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標清為0 }
  • 97. 練習3:優先權 97  LED3平時閃爍,按BTN1, LED0閃10次, BTN2則LED1 快閃15次 #include<ioAT89C52.h> #define LED0 P1_bit.P1_0 #define LED1 P1_bit.P1_1 #define LED2 P1_bit.P1_2 #define BTN1 P3_bit.P3_2 #define BTN2 P3_bit.P3_3 typedef unsigned char uint8; void delayms(uint8); void main() { BTN1 = 1; BTN2 = 1; LED0 = 1; LED1 = 1; TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標設為0 IE_bit.EX0 = 1; // 外部中斷0致能 IP_bit.PX0 = 1; IP_bit.PX1 = 0; TCON_bit.IE1 = 0; // 外部中斷1的中斷旗標設為0 IE_bit.EX1 = 1; // 外部中斷1致能 IE_bit.EA = 1; // 總中斷致能 while(1) { delayms(250); delayms(250); LED2 = ~LED2; } } void delayms(uint8 time) { uint8 n; while(time>0) { n = 162; while(n>0) n--; time --; } } #pragma vector = extern0 __interrupt void Int_Extern0(void) { uint8 i; for(i=0;i<20;i++){ LED0 = ~LED0; delayms(250); } TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標清為0 } #pragma vector = extern1 __interrupt void Int_Extern1(void) { uint8 i; for(i=0;i<30;i++){ LED1 = ~LED1; delayms(100); } TCON_bit.IE1 = 0; // 外部中斷1的中斷旗標清為0 }
  • 98. 練習4:全域變數 98  BTN2按完更改gflag以決定LED1之亮滅 typedef unsigned char uint8; volatile uint8 gflag = 0; void delayms(uint8); #pragma vector = extern0 __interrupt void Int_Extern0(void) { uint8 i; for(i=0;i<20;i++){ LED0 = ~LED0; delayms(250); } // gflag = ~gflag; TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標清為0 } #pragma vector = extern1 __interrupt void Int_Extern1(void) { uint8 i; for(i=0;i<30;i++){ LED1 = ~LED1; delayms(100); } gflag = ~gflag; TCON_bit.IE1 = 0; // 外部中斷1的中斷旗標清為0 } #pragma vector = extern0 __interrupt void Int_Extern0(void) { IE_bit.EA = 0; uint8 i; for(i=0;i<20;i++){ LED0 = ~LED0; delayms(250); } gflag = ~gflag; TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標清為0 IE_bit.EA = 1; } #pragma vector = extern1 __interrupt void Int_Extern1(void) { IE_bit.EA = 0; uint8 i; for(i=0;i<30;i++){ LED1 = ~LED1; delayms(100); } gflag = ~gflag; TCON_bit.IE1 = 0; // 外部中斷1的中斷旗標清為0 IE_bit.EA = 1; }
  • 99. 練習5:不可重進入函數 99 /********************************************************************************** Filename: exercise5-05.c Description: 不可重進入函數 開發板按鍵{INT0, INT1, T0, T1}, 分別對應到 {P3_2, P3_3, P3_4, P3_5} ************************************************************************************/ #include<ioAT89C52.h> #define LED0 P1_bit.P1_0 #define LED1 P1_bit.P1_1 #define LED2 P1_bit.P1_2 #define BTN1 P3_bit.P3_2 typedef unsigned char uint8; void delayms(uint8); volatile uint8 temp; void swap(uint8* x, uint8*y); void main() { BTN1 = 1; LED0 = 1; LED1 = 1; TCON_bit.IE0 = 0; // 外部中斷0的中斷旗標設為0 IE_bit.EX0 = 1; // 外部中斷0致能 IE_bit.EA = 1; // 總中斷致能 uint8 a = 1; uint8 b = 0; while(1) { if(a==1) LED1 = 0; else if (a==0) LED1 = 1; else LED2 = 0; delayms(250); swap(&a, &b); } } void swap(uint8* x, uint8* y) { uint8 i; temp = *x; LED0 = 0; for(i=0;i<10;i++) delayms(250); LED0 = 1; *x = *y; *y = temp; } void delayms(uint8 time) { uint8 n; while(time>0) { n = 162; while(n>0) n--; time --; } } #pragma vector = extern0 __interrupt void Int_Extern0(void) { IE_bit.EA = 0; uint8 a = 5, b =10; swap(&a, &b); TCON_bit.IE0 = 0; IE_bit.EA = 1; }