SlideShare a Scribd company logo
Chien-Jung Li
Sept. 2013
MCS-51 基礎實習
使用IAR Embedded Workbench (II)
定時器/計數器與中斷
Lab6: 運用定時器
MCS-51的定時/計數器
 實現定時功能的方法:
1) 使用微控器內部的定時/計數器
2) 軟體定時(空指令延遲函式):
軟體定時不佔用硬體資源,但佔用了CPU時間,降低CPU利用率。
3) 採用時基電路定時:
例如使用555電路,外接RC元件即可構成硬體定時電路。定時值
與定時範圍不能由軟體進行控制和修改,即不可程式設計。
4) 採用可程式設計晶片定時:
這種定時晶片的定時值及定時範圍很容易用軟體來確定和修改,
此種晶片定時功能強,使用靈活。在單晶片的定時/計數器不夠
用時,可考慮外接定時晶片擴充。
3
定時/計數器的結構和工作原理
GATE
C/T
M1
M0
GATE
C/T
M1
M0
TH1 TL1 TH0 TL0
TMODTCON
TF1
TR1
TF0
TR0
4
計時器/計數器的工作模式
T0M1 T0M0 MODE DESCRIPTION
0 0 0 13-bit timer/ counter / 0 ~ 8191
0 1 1 16-bit timer/ counter / 0 ~ 65535
1 0 2 8-bit auto-reload timer/ counter
1 1 3 Split mode (T0 acts as two 8-bits timers, T1 is stop)
5
工作模式0
6
TF1
TR1
TF0
TR0
GATE
C/T
M1
M0
GATE
C/T
M1
M0
1
&
≥1
1
0
T0
INT0
0
0
TH0 TL0
TCON TMOD
D0
D7
D7
D0
1
13
2X N 
工作模式1
7
TF1
TR1
TF0
TR0
GATE
C/T
M1
M0
GATE
C/T
M1
M0
1
&
≥1
1
0
T0
INT0
1
0
TH0 TL0
TCON
TMOD
D0
D7
D7
D0
16
2X N 
工作模式2
TF1
TR1
TF0
TR0
GATE
C/T
M1
M0
GATE
C/T
M1
M0
1
&
≥1
1
0
T0
INT0
1
0
TH0
TL0
TCON
TMOD
D0
D7
D7
D0
8
2X N 
8
工作模式3
TF1
TR1
TF0
TR0
GATE
C/T
M1
M0
GATE
C/T
M1
M0
1
&
≥1
1
0
T0
INT0
1
1
TH0
TL0
TCON
TMOD
D0 D7
D0
9
計時/計數器的使用
 初始化:
1) 對TMOD賦值,選擇T0或T1的工作模式
2) 計算計數初值,並寫入{TH0, TL0}或{TH1, TL1}
3) 欲產生中斷,則對IE賦值以開放中斷
4) 設置TR0或TR1以啟動計時/計數器
16
2 65,536 10,000 55,536 0xD8F0X N     
 
1
1 μs
12 MHz 12
cycleT  
10 ms
10,000
1 μs
N  
10
範例實習6
 請打開lab6_Timer
 練習1: 使用timer0定時中斷來使LED0閃爍
 練習2: 使用timer0定時中斷來使LED0每秒閃爍1次
 練習3: 使用timer0定時中斷來實現延時函式
 練習4: 使用定時中斷來依序點亮LED0~LED7
 練習5: 學習使用計數模式
 練習6: 使用Timer來掃描7段顯示器
 練習7: 中斷優先權實驗
11
練習1:Timer的基本使用法
12
/*****************************************************
Filename: exercise6-01.c
Description: 使用timer0定時中斷來使LED閃爍
*****************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
void Init_Timer0(void);
void main()
{
Init_Timer0();
LED0 = 1;
while(1);
}
void Init_Timer0(void)
{
TMOD |= 0x01; // 0000,0001 (mode 1, 16位元timer)
TH0 = 0x00; // modulus high-bits
TL0 = 0x00; // modulus low-bits
IE_bit.ET0 = 1; // timer0中斷致能
IE_bit.EA = 1; // 總中斷致能
TCON_bit.TR0 = 1; // timer0啟用
}
#pragma vector = timer0
__interrupt void Int_Timer0(void)
{
TCON_bit.TF0=0; // 硬體會自動清0, 習慣上軟體也會多做一次清0
TH0=0x00; // 如果計數值沒有要改變的話, TH0與TL0可以不用再設定
TL0=0x00;
LED0 = ~LED0;
}
// 實現現象: 65.5ms中斷一次, 一亮一滅需131 ms, 一秒內亮滅7.6次
練習2:設定溢位中斷發生的時間
13
/***********************************************************
Filename: exercise6-02.c
Description: 使用timer0定時中斷來使LED閃爍 /每1秒閃爍一次
************************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
volatile unsigned char k = 0;
void Init_Timer0(void);
void main()
{
Init_Timer0();
while(1);
}
void Init_Timer0(void)
{
TMOD |= 0x01; // 0000,0001 (mode 1, 16位元timer)
TH0 = 0x9E; // modulus high-bits 65536-25000=40536=0x9E58
TL0 = 0x58; // modulus low-bits
IE_bit.ET0 = 1; // timer0中斷致能
IE_bit.EA = 1; // 總中斷致能
TCON_bit.TR0 = 1; // timer0啟用
}
#pragma vector = timer0
__interrupt void Int_Timer0(void)
{
TCON_bit.TF0=0;
TH0=0x9E;
TL0=0x58;
k++;
if (k == 20) {
k = 0;
LED0 = ~LED0;
}
}
// 練習: 將TH0與TL0的設定改寫為
// TH0 = (65536-25000)/256;
// TL0 = (65536-25000)%256;
// 練習: 改用Timer1來實作
練習3:使用Timer實作的延時
14
/****************************************************************
Filename: exercise6-03.c
Description: 使用timer0實作硬體延遲函式, 並使LED0以1 Hz頻率閃爍
****************************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
typedef unsigned char uint8;
void delay500ms(void);
void Init_Timer0(void);
void main()
{
LED0 = 1;
while(1) {
LED0 = ~LED0;
delay500ms();
}
}
void delay500ms()
{
uint8 n;
for(n=0;n<10;n++) {
Init_Timer0();
while(TCON_bit.TF0 == 0);
TCON_bit.TF0 = 0;
}
TCON_bit.TR0 = 0;
IE_bit.ET0 = 0;
}
void Init_Timer0(void)
{
TMOD |= 0x01; // 0000,0001 (mode 1, 16位元timer)
TH0 = (65536-50000)/256; // high-bits
TL0 = (65536-50000)%256; // low-bits
IE_bit.ET0 = 1; // timer0中斷致能
IE_bit.EA = 1; // 總中斷致能
TCON_bit.TR0 = 1; // timer0啟用
}
#pragma vector = timer0
__interrupt void Int_Timer0(void)
{
; // do nothing
}
練習4:用ISR依序點亮LED0~LED7
15
/******************************************************
Filename: exercise6-04.c
Description: 使用timer0定時中斷來使LED0~LED7依序閃爍
*******************************************************/
#include<ioAT89C52.h>
#define LED P1
typedef unsigned char uint8;
volatile uint8 k = 0;
volatile uint8 m = 0;
void Init_Timer0(void);
void main()
{
Init_Timer0();
LED = 0xFF;
while(1);
}
void Init_Timer0(void)
{
TMOD |= 0x01;
TH0 = (65536-50000)/256;
TL0 = (65536-50000)%256;
IE_bit.ET0 = 1;
IE_bit.EA = 1;
TCON_bit.TR0 = 1;
}
#pragma vector = timer0
__interrupt void Int_Timer0(void)
{
TCON_bit.TF0 = 0;
TH0 = (65536-50000)/256;
TL0 = (65536-50000)%256;
k++;
if(k==10) {
k = 0;
LED = ~(1<<m);
m++;
if(m==8) m =0;
}
}
練習5:計數模式的使用
16
/***************************************************
Filename: exercise6-05.c
Description: 使用timer0計數5次後發生中斷來開關LED
****************************************************/
#include<ioAT89C52.h>
#define LED P1
typedef unsigned char uint8;
void Init_Timer0(void);
void main()
{
Init_Timer0();
LED = 0xFF;
while(1);
}
void Init_Timer0(void)
{
TMOD |= 0x06;
TH0 = (256-5);
TL0 = (256-5);
IE_bit.ET0 = 1;
IE_bit.EA = 1;
TCON_bit.TR0 = 1;
}
#pragma vector = timer0
__interrupt void Int_Counter0(void)
{
TCON_bit.TF0 = 0;
LED = ~LED;
}
T0M1 T0M0 MODE DESCRIPTION
0 0 0 13-bit timer/ counter / 0 ~ 8191
0 1 1 16-bit timer/ counter / 0 ~ 65535
1 0 2 8-bit auto-reload timer/ counter
1 1 3 Split mode (T0 acts as two 8-bits timers, T1 is stop)
練習6: 7-Seg改Timer掃描
17
/*******************************************************
Filename: exercise6-06_TimerScan.c
Description: 使用Timer做scan
********************************************************/
#include<ioAT89C52.h>
#define seg_set P2_bit.P2_6
#define pos_set P2_bit.P2_7
#define SEG7LED P0
#define POS7LED P0
#define POS(n) (1 << (n))
typedef unsigned char uint8;
volatile uint8 count = 0;
void Timer0_Init(void);
void DispScrClr(void);
void DispShowPos(uint8 pos);
void DispShowSym(uint8 sym_num, uint8 dp);
void DispSym_at_Pos(uint8 pos, uint8 symbol_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 = 0;
uint8 pos_num = 0;
Timer0_Init();
while(1) {
if(count==6) {
pos_set = 1;
POS7LED = 0xFF;
pos_set = 0;
}
if (count == 10) {
count = 0;
DispSym_at_Pos(POS(pos_num),symbol_num,0);
pos_num++;
symbol_num++;
if (pos_num ==8) {
symbol_num=0;
pos_num=0;
}
}
}
}
練習6: 7-Seg改Timer掃描
18
void DispScrClr(void)
{
略
}
void DispShowPos(uint8 pos)
{
略
}
void DispShowSym(uint8 sym_num, uint8 dp)
{
略
}
void DispSym_at_Pos(uint8 pos, uint8 symbol_num, uint8 dp)
{
DispShowSym(symbol_num, dp);
DispShowPos(pos);
}
void delayms(uint8 time)
{
略
}
void Timer0_Init(void)
{
TMOD |= 0x01; // Timer0, mode1, 16-bits
TH0 = (65536-200)/256;
TL0 = (65536-200)%256;
TCON_bit.TR0 = 1;
IE_bit.ET0 = 1;
IE_bit.EA = 1;
}
#pragma vector = timer0
__interrupt void Int_Timer0(void) // 0.1ms
{
TH0=(65536-200)/256;
TL0=(65536-200)%256;
count++;
}
練習7:中斷優先權的實驗
19
 C51的預設中斷優先權如下表:
 請設定優先權SFR,使中斷優先順序為
T1  INT1  INT0  T0
 練習:請自行寫一個程式驗證
中斷源 中斷旗標 ISR入口 優先權
外部中斷0 IE0 0x0003 高
定時/計數器0 (T0) TF0 0x000B
外部中斷1 IE1 0x0013
定時/計數器0 (T1) TF1 0x001B
串列埠 RI或TI 0x0023 低
Lab7: 喇叭
實習7:喇叭發聲實驗
21
 請打開lab7_speaker
 練習1: 發出基頻率為500 Hz的聲音
 練習2: 警報音
 練習3: 救護車
 練習4: 消防車
練習1:產生基頻為500 Hz的聲音
22
/*****************************************
Filename: exercise7-01.c
Description: Play a sound of 500 Hz
******************************************/
#include<ioAT89C52.h>
typedef unsigned char uint8;
#define Speaker P2_bit.P2_3
void delayms(uint8 time);
void main()
{
while(1)
{
delayms(1);
Speaker = ~Speaker;
}
}
/*********************************************************
* @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 --;
}
}
練習2:警告音
23
/**************************************
Filename: exercise7-02.c
Description: Warning Sound
***************************************/
#include<ioAT89C52.h>
typedef unsigned char uint8;
#define Speaker P2_bit.P2_3
void delayms(uint8 time);
void Init_Timer0(void);
volatile uint8 freq = 0;
void main()
{
Init_Timer0();
while(1)
{
delayms(1);
freq++;
}
}
void Init_Timer0(void)
{
TMOD |= 0x01; // mode1, 16-bits timer
TH0 = 0x00;
TL0 = 0x00;
IE_bit.EA = 1; // Enable Int
IE_bit.ET0 = 1; // Enable Timer0 Int
TCON_bit.TR0 = 1; // Enable Timer0
}
#pragma vector = timer0
__interrupt void Int_Timer0(void)
{
TH0 = 0xFE;
TL0 = freq;
Speaker = !Speaker;
}
/***************************************
* @fn delayms
* @brief delay with ms
* @param time = 0 ~ 255
* @return None
***************************************/
void delayms(uint8 time)
{
uint8 n;
while(time>0)
{
n = 162;
while(n>0) n--;
time --;
}
}
void Init_Timer0(void)
{
TMOD |= 0x01; // mode1, 16-bits timer
TH0 = 0x00;
TL0 = 0x00;
IE_bit.EA = 1; // Enable Int
IE_bit.ET0 = 1; // Enable Timer0 Int
TCON_bit.TR0 = 1; // Enable Timer0
}
#pragma vector = timer0
__interrupt void Int_Timer0(void)
{
TH0 = 0xFE;
TL0 = freq;
Speaker = !Speaker;
}
/****************************************
* @fn delayms
* @brief delay with ms
* @param time = 0 ~ 255 ms
* @return None
****************************************/
void delayms(uint8 time)
{
uint8 n;
while(time>0)
{
n = 162;
while(n>0) n--;
time --;
}
}
練習3:救護車
24
/****************************************
Filename: exercise7-03.c
Description: Sound of the Ambulance
*********************************************/
#include<ioAT89C52.h>
typedef unsigned char uint8;
#define Speaker P2_bit.P2_3
void delayms(uint8 time);
void Init_Timer0(void);
volatile uint8 freq = 0;
void main()
{
uint8 i;
Init_Timer0();
while(1)
{
freq = 0;
for(i=0;i<60;i++)
delayms(10);
freq = 100;
for(i=0;i<60;i++)
delayms(10);
}
}
void Init_Timer0(void)
{
TMOD |= 0x01; // mode1, 16-bits timer
TH0 = 0x00;
TL0 = 0x00;
IE_bit.EA = 1; // Enable Int
IE_bit.ET0 = 1; // Enable Timer0 Int
TCON_bit.TR0 = 1; // Enable Timer0
}
#pragma vector = timer0
__interrupt void Int_Timer0(void)
{
TH0 = 0xFE;
TL0 = freq;
Speaker = !Speaker;
}
/***************************************
* @fn delayms
* @brief delay with ms
* @param time = 0 ~ 255 ms
* @return None
***************************************/
void delayms(uint8 time)
{
uint8 n;
while(time>0)
{
n = 162;
while(n>0) n--;
time --;
}
}
練習4:消防車
25
/*********************************************
Filename: exercise7-04.c
Description: Sound of the fire engine
**********************************************/
#include<ioAT89C52.h>
typedef unsigned char uint8;
#define Speaker P2_bit.P2_3
void delayms(uint8 time);
void Init_Timer0(void);
volatile uint8 freq = 0;
void main()
{
uint8 i;
Init_Timer0();
while(1)
{
freq = 0;
for(i=0;i<200;i++) {
delayms(10);
freq = i;
}
freq = 200;
for(i=200;i>0;i--) {
delayms(10);
freq = i;
}
}
}
Lab8: 串列通訊
計算機通訊
27
 單工:單工是指資料傳輸僅能沿一個方向,不能實現反向傳輸。
 半雙工:半雙工是指資料傳輸可以沿兩個方向,但需要分時進行。
 全雙工:全雙工是指數據可以同時進行雙向傳輸。
計算機數據通訊基礎
 PC與外部設備或PC與PC間的資訊交換,具有並列和
串列通訊兩種方式。(多數系統經常採用串列通訊)
1
0
1
0
1
1
0
0
D0 D7
28
同步與非同步通訊
 同步通訊:發送方與接收方使用相同clock。
 非同步通訊:發送方與接收方使用各自的clock。
為使雙方的收發協調,雙方的clock要盡量一致。
11100110010100100 1 101001000 1 111001100 1
29
0 1 1 0 1
非同步通訊的資料格式
 非同步通訊的特點:
不要求收發雙方clock嚴格一致、實現容易,但每個字元要附加
2~3位元用於起/止位元與校驗位元,各frame之間因為還有間隔,
因此傳輸效率不高。
30
串列通訊的數據校驗(錯誤檢查)
 同位檢查 (Parity Check)
在發送資料尾隨1位同位檢查位元(1或0)。
奇同位:「數據中1」與「校驗位1」的個數和為奇數
偶同位:「數據中1」與「校驗位1」的個數和為偶數
接收字元時,對「1的個數」做校驗,若不一致則表示資料錯誤。
 碼和校驗 (Check Sum)
Check Sum是發送方將所發資料塊求和(或各位元組XOR),產生一
個位元組的校驗字元(即checksum)附加到資料塊的尾巴。接收方接
收資料同時對資料塊求和(或各位元組EXOR),將所得的結果與發
送方的checksum做比較,若不一致則表示資料錯誤。
 迴圈冗餘校驗 (CRC)
此校驗是通過某種數學運算實現有效資訊與校驗位元之間的迴圈
校驗,常用於對磁片資訊的傳輸、存儲區的完整性校驗等。這種
校驗方法偵錯能力強,但實現上較複雜。
31
串列通訊RS-232介面
 RS-232C:
EIA(美國電子工業協會)於1969年修訂。RS-232C定義了資料終端
設備(DTE)與資料通訊設備(DCE)之間的物理介面標準。
96
51
2514
131
96
51
2514
131
TXD TXD
RXD RXD
TXD
RXD
RTS
TXD
RXD
RTS
DSRDSR
32
RS232與TTL的電氣介面轉換
33
MCS-51的串列埠(UART)
• 兩個物理上獨立的接收、發送緩衝器SBUF,但佔用同一位址99H。
• SCON暫存器設定串列工作方式、接收/發送控制及設置狀態旗標。
≥1
SBUF
TI
RI
A
TXD
RXD
SMOD
0
1
TH1 TL1
SBUF
÷2
÷16
34
80C51的串列埠(UART)
SM0 SM1 MODE DESCRIPTION BAUD RATE
0 0 0 8-bit Shift Register 1/12 the quartz frequency
0 1 1 8-bit UART Determined by the timer 1
1 0 2 9-bit UART 1/32 the quartz frequency (1/64 the quartz frequency)
1 1 3 9-bit UART Determined by the timer 1
35
UART Mode 0:同步移位暫存器
74LS164
RX
D
TXD
P1.0
80C51
CLRCLK
A
B
GND
74LS165
RX
D
TXD
P1.080C51
S/LCLK
Q
GND
36
37
UART Mode 1:有起始與停止位元
UART Mode 2:起始、停止、同位檢查
38
鮑率的計算(Baud Rate)
MODE BAUD RATE SMOD位元 (於PCON暫存器)
0 fosc/12
1 (T1溢出率) * (SMOD+1) * fosc/32 SMOD = 1 (or 0)
2 (SMOD+1) * fosc/64 SMOD = 1 (or 0)
3 (T1溢出率) * (SMOD+1) * fosc/32 SMOD = 1 (or 0)
T1 溢出率 = fosc /{12×[ 256  (TH1) ]}
39
多機通訊
40
總而言之:UART工作設定
 初始化UART的設定步驟:
1) 設定產生串列baud rate的計時器1
 設定TMOD暫存器以決定T1的工作模式
 計算T1的計數初值,並將其載入TH1、TL1
 設定TCON以啟動T1 (TR1位元)
2) 設定串列埠控制與工作模式
 設定SCON暫存器以決定串列部的控制與工作模式
3) 設定串列發射與接收的中斷控制
 設定IE(與IP)以啟用串列埠中斷
41
實習8:
42
 請打開lab8_UART
 練習1: 使用UART通訊來點亮LED
 練習2: 發送數據與字串給電腦
 練習3: 結合練習1與練習2(C51可收可發)
 練習4: C51收到2個Bytes後回傳「收送次數」+
「數據的”字串”」給電腦,收送20次後覆歸回1。
練習1:使用UART通訊來點亮LED
43
/*************************************************
Filename: exercise8-01.c
Description: UART - Mode 1 8-bits receiving
*************************************************/
#include<ioAT89C52.h>
#define LED P1
typedef unsigned char uint8;
void Uart_Init(void);
void main()
{
Uart_Init();
while(1);
}
void Uart_Init(void)
{
TMOD |= 0x20; // Timer1, Mode 2, 8-bit auto-reloader
TH1 = 0xF3; // 253, 2400 bps
TL1 = 0xF3; // 253, count to 255 -> reload with TH1
TCON_bit.TR1 = 1; // Timer1 Enable
SCON_bit.SM0 = 0; // Mode 1: 8-bit UART
SCON_bit.SM1 = 1; // Baud rate determined by T1 SM0=0/SM1=1
SCON_bit.RI = 0; // Clear RI flag
SCON_bit.REN = 1; // RX enable
IE_bit.ES = 1; // Enable serial interrupt
IE_bit.EA = 1; // Enable interrupt
}
#pragma vector = RI_int
__interrupt void Int_UartRX(void)
{
IE_bit.EA = 0;
LED = ~SBUF;
SCON_bit.RI = 0;
IE_bit.EA = 1;
}
練習2
/***************************************************
Filename: exercise8-02.c
Description: UART - Mode 1 8-bits transmitting
****************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
#define BTN1 P3_bit.P3_2
#define BTN2 P3_bit.P3_3
typedef unsigned char uint8;
void Uart_Init(void);
void sendByte(uint8 data);
void sendStr(unsigned char *s);
void delayms(uint8 time);
void main()
{
Uart_Init();
while(1) {
if (BTN1 == 0) {
delayms(30);
while(BTN1==0);
sendByte(0xA2);
}
if (BTN2 == 0) {
delayms(30);
while(BTN2==0);
sendStr("TEST String Sendingn");
}
}
}
void Uart_Init(void)
{
TMOD |= 0x20; // Timer1, Mode 2, 8-bit auto-reload
TH1 = 0xF3; // 253, 2400 bps
TL1 = 0xF3; // 253, count to 255 -> reload with TH1
TCON_bit.TR1 = 1; // Timer1 Enable
SCON_bit.SM0 = 0; // Mode 1: 8-bit UART
SCON_bit.SM1 = 1; // Baud rate determined by T1
SCON_bit.TI = 0; // Clear TI flag
IE_bit.ES = 1; // Enable serial interrupt
IE_bit.EA = 1; // Enable interrupt
}
void sendByte(uint8 data)
{
SBUF = data;
LED0 = 0;
while(!SCON_bit.TI);
SCON_bit.TI = 0;
LED0 = 1;
}
void sendStr(unsigned char *s)
{
while(*s!='0')
{
sendByte(*s);
s++;
}
}
void delayms(uint8 time)
{
略
}
#pragma vector = TI_int
__interrupt void Int_UartTI(void)
{
}
44
練習3
/*********************************************
Filename: exercise8-03.c
Description: UART - Mode 1 8-bits TX/RX
**********************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
#define LED P1
#define BTN1 P3_bit.P3_2
#define BTN2 P3_bit.P3_3
typedef unsigned char uint8;
void Uart_Init(void);
void sendByte(uint8 data);
void sendStr(unsigned char *s);
void delayms(uint8 time);
void main()
{
Uart_Init();
while(1) {
if (BTN1 == 0) {
delayms(30);
while(BTN1==0);
sendByte(0xA2);
}
if (BTN2 == 0) {
delayms(30);
while(BTN2==0);
sendStr("TEST String Sendingn");
}
}
}
void Uart_Init(void)
{
TMOD |= 0x20; // Timer1, Mode 2, 8-bit auto-reloader
TH1 = 0xF3; // 253, 2400 bps
TL1 = 0xF3; // 253, count to 255 -> reload with TH1
TCON_bit.TR1 = 1; // Timer1 Enable
SCON_bit.SM0 = 0; // Mode 1: 8-bit UART
SCON_bit.SM1 = 1; // Baud rate determined by T1
SCON_bit.TI = 0; // Clear TI flag
SCON_bit.RI = 0; // Clear RI flag
SCON_bit.REN = 1; // RX enable
IE_bit.ES = 1; // Enable serial interrupt
IE_bit.EA = 1; // Enable interrupt
}
void sendByte(uint8 data)
{
LED0 = ~LED0;
SBUF = data;
while(!SCON_bit.TI);
SCON_bit.TI = 0;
LED0 = ~LED0;
}
void sendStr(unsigned char *s)
{
while(*s!='0')
{
sendByte(*s);
s++;
}
}
void delayms(uint8 time)
{
略
}
#pragma vector = TI_int
__interrupt void Int_UartService(void)
{
if(SCON_bit.RI) {
LED = ~SBUF;
SCON_bit.RI = 0;
}
}
45
練習4
46
/**********************************************
Filename: exercise8-04.c
Description: UART - Mode 1 8-bits TX/RX
**********************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
#define LED P1
#define BTN1 P3_bit.P3_2
#define BTN2 P3_bit.P3_3
typedef unsigned char uint8;
typedef unsigned char uchar;
void Uart_Init(void);
void sendByte(uint8 data);
void sendStr(uchar *s);
void delayms(uint8 time);
uint8 count = 1;
uint8 data_len = 0;
uint8 RX_data[2];
void Dec2ASCII(uint8 data, uchar *buf);
void Hex2ASCII(uint8 data, uchar *buf);
void rsp_back(void);
void main()
{
Uart_Init();
while(1)
{
if (data_len >= 2) {
data_len =0;
rsp_back();
count++;
if(count == 21) count = 1;
}
}
}
/******************************************************************************************
* @fn Uart_Init
* @brief Initilize the Timer 1 for baud rate setting, UART Mode, Interrupt Flags, ES, EA
* @param None
******************************************************************************************/
void Uart_Init(void)
{
TMOD |= 0x20; // Timer1, Mode 2, 8-bit auto-reloader
TH1 = 0xF3; // 253, 2400 bps
TL1 = 0xF3; // 253, count to 255 -> reload with TH1
TCON_bit.TR1 = 1; // Timer1 Enable
SCON_bit.SM0 = 0; // Mode 1: 8-bit UART
SCON_bit.SM1 = 1; // Baud rate determined by T1 SM0=0/SM1=1
SCON_bit.TI = 0; // Clear TI flag
SCON_bit.RI = 0; // Clear RI flag
SCON_bit.REN = 1; // RX enable
IE_bit.ES = 1; // Enable serial interrupt
IE_bit.EA = 1; // Enable interrupt
}
/*****************************************************************************************
* @fn sendByte
* @brief Send 1-byte data via UART TX (just simply write SBUF)
* @param data is the single byte to send
*****************************************************************************************/
void sendByte(uint8 data)
{
LED0 = ~LED0;
SBUF = data;
while(!SCON_bit.TI);
SCON_bit.TI = 0;
LED0 = ~LED0;
}
47
/*****************************************************************************************
* @fn sendStr
* @brief Send a string via UART TX (invoke sendByte() until *s == '0')
* @param *s points to the string (char array)
* @return None
****************************************************************************************/
void sendStr(uchar *s)
{
while(*s!='0')
{
sendByte(*s);
s++;
}
}
/********************************************************************************
* @fn Hex2ASCII
* @brief Convert HEX (data) to String (ASCII)
* @param data: hex to convert; *buf is the buffer to save the converted string
* @return None
********************************************************************************/
void Hex2ASCII(uint8 data, uchar *buf)
{
uint8 hi_nip, low_nip;
low_nip = data % 16;
hi_nip = data / 16;
if(low_nip < 10)
low_nip = low_nip + 0x30;
else
low_nip = low_nip + 0x37;
if(hi_nip < 10)
hi_nip = hi_nip + 0x30;
else
hi_nip = hi_nip + 0x37;
*buf = hi_nip;
buf++;
*buf = low_nip;
}
48
49
/***************************************************************************************************
* @fn Dec2ASCII
* @brief Convert DEC (data) to String (ASCII)
* @param data: dec to convert; *buf is the buffer to save the converted string
* @return None
***************************************************************************************************/
void Dec2ASCII(uint8 data, uchar *buf)
{
uint8 dec_pos0, dec_pos1;
dec_pos0 = data % 10;
dec_pos1 = data / 10;
dec_pos0 = dec_pos0 + 0x30;
dec_pos1 = dec_pos1 + 0x30;
*buf = dec_pos1;
buf++;
*buf = dec_pos0;
}
/***************************************************************************************************
* @fn delayms
* @brief delay with ms
* @param time = 0 ~ 255, the maximum delay is 255 ms
* @return None
***************************************************************************************************/
void delayms(uint8 time)
{
略
}
50
/***************************************************************************************************
* @fn rsp_back
* @brief After MCU receving "2-bytes", it returns the string form of this "2-bytes data"
* with the number of counts. When counts achieves 20, then reset it to 1.
* @param None
* @return None
***************************************************************************************************/
void rsp_back(void)
{
uchar show_count[3];
uchar show_data[3];
Dec2ASCII(count, show_count);
show_count[2] = '0';
Hex2ASCII(RX_data[0], show_data);
show_data[2] = '0';
sendStr("count: ");
sendStr(show_count);
sendStr(", data: 0x");
sendStr(show_data);
sendStr(" 0x");
Hex2ASCII(RX_data[1], show_data);
show_data[2] = '0';
sendStr(show_data);
sendStr("n");
}
#pragma vector = RI_int
__interrupt void Int_UartService(void)
{
IE_bit.EA = 0;
if(SCON_bit.RI) {
RX_data[data_len] = SBUF;
data_len++;
SCON_bit.RI = 0;
}
IE_bit.EA = 1;
}
Lab9: ADC與DAC
A/D轉換器
52
8
1
Resolution 10 V 39 mV
2
 
ADC與MCU的介面
53
多通道的ADC
54
ADC0804 – Timing Diagram
55
實習9 (I)
56
 練習1:電壓計
 練習2:將練習1的讀取值改以電壓值顯示
 練習3:光線感測器
 練習4:溫度感測器
練習1: 使用ADC讀取可變電阻分壓
57
/***************************************************
Filename: exercise9-01.c
Description: ADC Demo
***************************************************/
#include<ioAT89C52.h>
#define ADC_WR P3_bit.P3_6
#define ADC_RD P3_bit.P3_7
#define ADC_CS P2_bit.P2_2
#define ADC_DATA_PORT P1
#define seg_set P2_bit.P2_6
#define pos_set P2_bit.P2_7
#define SEG7LED P0
#define POS7LED P0
#define POS(n) (1 << (n))
typedef unsigned char uint8;
void DispScrClr(void);
void DispShowPos(uint8 pos);
void DispShowSym(uint8 sym_num, uint8 dp);
void DispSym_at_Pos(uint8 pos, uint8 symbol_num, uint8 dp);
void delayms(uint8 time);
void delay10us(uint8 time);
void ADC_SampleOneShot(void);
uint8 ADC_SampledDigits(void);
// 符號表 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()
{
uint8 a, ad_rdval = 0;
uint8 Rd_in[3];
DispScrClr();
while(1)
{
ADC_SampleOneShot();
for (a=200; a>0; a--) {
DispSym_at_Pos(POS(5), Rd_in[0], 0);
delayms(1);
DispSym_at_Pos(POS(6), Rd_in[1], 0);
delayms(1);
DispSym_at_Pos(POS(7), Rd_in[2], 0);
delayms(1);
}
ad_rdval = ADC_SampledDigits();
Rd_in[0] = ad_rdval/100;
Rd_in[1] = (ad_rdval%100)/10;
Rd_in[2] = (ad_rdval%100)%10;
}
}
// 7段顯示器的driver
void DispScrClr(void)
{
略
}
void DispShowPos(uint8 pos)
{
略
}
void DispShowSym(uint8 sym_num, uint8 dp)
{
略
}
void DispSym_at_Pos(uint8 pos, … 略)
{
略
}
void delayms(uint8 time)
{
略
}
void delay10us(uint8 time)
{
uint8 n;
while(time>0) {
n = 4;
while(n>0) n--;
time --;
}
}
58
/**********************************************
* @fn ADC_SampleOneShot
* @brief Read the analog input signal
*********************************************/
void ADC_SampleOneShot(void)
{
ADC_CS = 0;
delay10us(10);
ADC_WR = 0;
delay10us(10);
ADC_WR = 1;
delay10us(10);
ADC_CS = 1;
}
/*********************************************
* @fn ADC_SampledDigits
* @brief Output the sampled digits
*********************************************/
uint8 ADC_SampledDigits(void)
{
uint8 ad_rdval;
ADC_CS = 0;
delay10us(1);
ADC_RD = 0;
delay10us(1);
ad_rdval = ADC_DATA_PORT;
delay10us(1);
ADC_RD = 1;
delay10us(1);
ADC_CS = 1;
delay10us(1);
return ad_rdval;
}
練習2: 將讀取值換算成電壓值
59
void main()
{
uint8 a, ad_rdval = 0;
unsigned int ad_rdval_dec = 0;
uint8 Rd_in[3];
uint8 Rd_in_dec[3];
DispScrClr();
while(1)
{
ADC_SampleOneShot();
for (a=200; a>0; a--){
DispSym_at_Pos(POS(5), Rd_in[0], 0);
delayms(1);
DispSym_at_Pos(POS(6), Rd_in[1], 0);
delayms(1);
DispSym_at_Pos(POS(7), Rd_in[2], 0);
delayms(1);
DispSym_at_Pos(POS(0), Rd_in_dec[0], 1);
delayms(1);
DispSym_at_Pos(POS(1), Rd_in_dec[1], 0);
delayms(1);
DispSym_at_Pos(POS(2), Rd_in_dec[2], 0);
delayms(1);
}
ad_rdval = ADC_SampledDigits();
Rd_in[0] = ad_rdval/100;
Rd_in[1] = (ad_rdval%100)/10;
Rd_in[2] = (ad_rdval%100)%10;
ad_rdval_dec = 20*ad_rdval;
Rd_in_dec[0] = ad_rdval_dec/1000;
Rd_in_dec[1] = (ad_rdval_dec%1000)/100;
Rd_in_dec[2] = (ad_rdval_dec%100)/10;
// 5V with 8bits, Resolution = 5/256 = 20 mV
// 1V/20mV = 50
}
}
光線感測器(使用光敏電阻)
60
 光敏電阻的電阻值隨光強度增加而減小,
光強度減小則電阻增大。常用的製作材料
有硫化鎘、硒、硫化鋁、硫化鉛和硫化鉍
等材料。這些材料具有在特定波長的光照
射下,其阻值迅速減小的特性。
 光敏電阻器在電路中用R或RL、RG表示。
 暗電阻:完全沒有光照狀態時(室溫)的電
阻值,與暗電阻相對應的電流為暗電流。
 亮電阻:在充足光線照射的狀態時(室溫)
的電阻值為亮電阻,與亮電阻相對應的電
流為亮電流。
溫度感測器(使用熱敏電阻)
61
 目前熱敏電阻應用廣泛且種類繁多,此開發板是採用
負溫度係數熱敏電阻器TTC103(10K),常見用於家用電
器如空調、電冰箱、電扇、電鍋、洗衣機、飲水機、
電視機與收音機等。
 由於熱敏電阻與溫度的變化曲線是非線性的,又8位元
MCU的計算能力有限,所以為了簡單實用,通常會使
用查表法來算取溫度值,而不用公式來計算(複雜)。溫
度精度值取決於AD取樣的精度、溫度錶格精度和熱敏
電阻精度。
練習3/4: 亮度/溫度感測
/*************************************************
Filename: exercise9-03.c
Description: Light/Temp Sensor Using ADC
**************************************************/
#include<ioAT89C52.h>
… 略 …
#define Speaker P2_bit.P2_3
… 略 …
void DispScrClr(void);
… 略 …
void Init_Timer0(void);
volatile uint8 freq = 0;
uint8 symbols[]={
… 略 …
void main()
{
uint8 a, ad_rdval = 0;
uint8 Rd_in[3];
DispScrClr();
Init_Timer0();
while(1)
{
ADC_SampleOneShot();
for (a=200; a>0; a--){
DispSym_at_Pos(POS(5), Rd_in[0], 0);
delayms(1);
DispSym_at_Pos(POS(6), Rd_in[1], 0);
delayms(1);
DispSym_at_Pos(POS(7), Rd_in[2], 0);
delayms(1);
}
ad_rdval = ADC_SampledDigits();
Rd_in[0] = ad_rdval/100;
Rd_in[1] = (ad_rdval%100)/10;
Rd_in[2] = (ad_rdval%100)%10;
if (ad_rdval<125) {
TCON_bit.TR0 = 0 // Enable Timer0
delayms(1);
freq++;
} else {
TCON_bit.TR0 = 0; // Disable Timer0
}
}
}
// ADC的driver
void ADC_SampleOneShot(void)
{
略
}
uint8 ADC_SampledDigits(void)
{
略
}
// 7段顯示器的driver
略
62
63
void delayms(uint8 time)
{
略
}
void delay10us(uint8 time)
{
略
}
void Init_Timer0(void)
{
TMOD |= 0x01; // mode1, 16-bits timer
TH0 = 0x00;
TL0 = 0x00;
IE_bit.EA = 1; // Enable Int
IE_bit.ET0 = 1; // Enable Timer0 Int
TCON_bit.TR0 = 1; // Enable Timer0
}
#pragma vector = timer0
__interrupt void Int_Timer0(void)
{
TH0 = 0xFE;
TL0 = freq;
Speaker = !Speaker;
}
D/A轉換器
64
FS
2n
V
8
5 V 5 V
19.53 mV
2 256
 
12
5 V 5 V
1.22 mV
2 4096
 
DAC0832(/0830/0831)內部架構
 解析度為8位元,內部有輸入資料暫存器,可與MCU銜接
 以電流形式輸出,電流建立時間1μs
 資料輸入可採用雙緩衝、單緩衝或直通方式
 輸入邏輯電位與TTL電位規格相容
 單一電源供電(+5V~+15V)
DI7~DI0
ILE
CS
WR1
WR2 XFER
VREF
IOUT2
IOUT1
Rfb
AGND
VCC
&&
&
LE1 LE2
65
66
DAC與MCU的介面
DAC0832 Timing Diagram
67
DAC0832與80C51的介面
 單緩衝工作:適用於只有一路類比輸出,或有幾路類比輸出但並
不要求同步的系統。
 雙緩衝工作:多路D/A轉換輸出,如果要求同步進行,就應該採用
雙緩衝器同步方式
 直通工作:CS、WR及XFER全部接地而ILE接VCC時,DAC0832就處
於直通工作方式,數位量一旦輸入就直接進入DAC暫存器,進行
D/A轉換。
80C51
P2.7
P0
WR
CS
XFER
WR1
WR2
ILE
VCC
+5V

+
Rfb
VO
DAC0832
IOUT1
IOUT2
1 kΩ
1 MΩDI0
DI7
DGNDVSS
68
80C51
P2.7
P0
WR
CS
XFER
WR1
WR2
ILE
VCC
DAC0832(1)
DI0
DI7
CS
XFER
WR1
WR2
ILE
VCC
+5V
DAC0832(2)
DI0
DI7
P2.6
P2.5
實習9 (II)
69
 練習5:使用DAC輸出改變LED亮度
 練習6:每按一次按鍵增加一點亮度
 練習7:脈波寬度調變(1位元DAC)
練習5:使用DAC輸出來改變LED亮度
70
/********************************************
Filename: exercise9-05.c
Description: DAC Demo
********************************************/
#include<ioAT89C52.h>
#define DAC_CS P3_bit.P3_6
#define DAC_WR P3_bit.P3_2
#define DAC_DATA_PORT P0
#define seg_set P2_bit.P2_6
#define pos_set P2_bit.P2_7
typedef unsigned char uint8;
void delayms(uint8 time);
void delay10us(uint8 time);
void DAC_OneShot(uint8 *digits);
void main()
{
// Because the DAC uses P0 port,
// here we turn of the 7-seg LED
seg_set = 0;
pos_set = 0;
uint8 dac_val = 255;
while(1)
{
DAC_OneShot(&dac_val);
delayms(5);
dac_val++;
}
}
/*********************************************************
* @fn DAC_OneShot
* @brief Convert a digit byte to analog value
* @param *digits points to the value of the digit byte
* @return None
********************************************************/
void DAC_OneShot(uint8 *digits)
{
DAC_DATA_PORT = *digits;
DAC_CS = 0;
delay10us(1);
DAC_WR = 0;
delay10us(1);
DAC_WR = 1;
delay10us(10);
DAC_CS = 1;
}
void delayms(uint8 time)
{
…略…
}
void delay10us(uint8 time)
{
…略…
n = 4;
}
練習6:按鍵增加LED亮度
71
/*****************************************
Filename: exercise9-06.c
Description: DAC Demo
*****************************************/
#include<ioAT89C52.h>
#define DAC_CS P3_bit.P3_6
#define DAC_WR P3_bit.P3_2
#define DAC_DATA_PORT P0
#define seg_set P2_bit.P2_6
#define pos_set P2_bit.P2_7
#define BTN1 P3_bit.P3_3
typedef unsigned char uint8;
void delayms(uint8 time);
void delay10us(uint8 time);
void DAC_OneShot(uint8 *digits);
void main()
{
seg_set = 0; // just turn-off 7-seg
pos_set = 0;
uint8 dac_val = 0;
DAC_OneShot(&dac_val);;
while(1)
{
DAC_OneShot(&dac_val);
DAC_OneShot(&dac_val);
if (BTN1 == 0) {
delayms(50);
if (BTN1 == 0){
while(BTN1 == 0);
dac_val = dac_val+10;
if(dac_val>240) dac_val = 0;
}
}
}
}
void DAC_OneShot(uint8 *digits)
{
略
}
void delayms(uint8 time)
{
略
}
void delay10us(uint8 time)
{
略
}
練習7:會呼吸的LED燈
72
sin(22.5)  176
sin(45)  218
sin(0)0+(256/2)  128
uint8 sine[16] = {128, 176, 218, 245, 255, 245, 218, 176,
128, 79, 37, 10, 0, 10, 37, 79};
uint8 sine[16] = {128, 176, 218, 245, 255, 245, 218, 176,
128, 79, 57, 30, 20, 20, 57, 99};
練習7:會呼吸的LED燈
73
/******************************************
Filename: exercise9-07.c
Description: DAC Demo: Breathing LED
******************************************/
#include<ioAT89C52.h>
#define DAC_CS P3_bit.P3_6
#define DAC_WR P3_bit.P3_2
#define DAC_DATA_PORT P0
#define seg_set P2_bit.P2_6
#define pos_set P2_bit.P2_7
#define BTN1 P3_bit.P3_3
typedef unsigned char uint8;
void delayms(uint8 time);
void delay10us(uint8 time);
void DAC_OneShot(uint8 *digits);
// uint8 sine[16] = {128, 176, 218, 245, 255, 245, 218, 176,
// 128, 79, 37, 10, 0, 10, 37, 79};
uint8 sine[16] = {128, 176, 218, 245, 255, 245, 218, 176,
128, 79, 57, 30, 20, 20, 57, 99};
void main()
{
uint8 i=0;
seg_set = 0; // just turn-off 7-seg
pos_set = 0;
DAC_OneShot(0);
while(1)
{
DAC_OneShot((sine+i));
delayms(150);
i++;
if (i==16) i=0;
}
}
void DAC_OneShot(uint8 *digits)
{
略
}
void delayms(uint8 time)
{
略
}
void delay10us(uint8 time)
{
略
}
週期性脈波之Duty Cycle與其平均值
74
脈波寬度調變(Pulse-Width Modulation)
75
 PWM是將類比訊號轉換為脈波形式的一種技術(當ADC
使用,資訊以脈波寬度表示)。
 PWM訊號經低通濾波,可恢復為原來的類比訊號(當
DAC使用) 。
如何用計時器完成PWM功能
76
PWM就是一直在改變Duty Cycle的脈波
77
練習8: 會呼吸的LED燈(使用PWM)
78
/****************************************************
Filename: exercise9-08.c
Description: PWM DAC Demo
****************************************************/
#include<ioAT89C52.h>
#define LED0 P1_bit.P1_0
typedef unsigned char uint8;
uint8 sine_duty[16] = {50, 70, 85, 96, 100, 96, 85, 70,
50, 30, 14, 4, 0, 4, 14, 30};
uint8 count = 0;
void PWM_LED0(uint8 *count, uint8* duty);
void Init_Timer0(void);
void main()
{
Init_Timer0();
LED0 = 1;
uint8 i = 0;
while(1)
{
if (count==255) {
count = 0;
i++;
if (i==16) i=0;
}
PWM_LED0(&count, (sine_duty+i));
}
}
void PWM_LED0(uint8 *count, uint8* duty)
{
unsigned int comp_val;
comp_val = (*duty)*255/100;
if (*count > comp_val) {
LED0 = 1;
} else {
LED0 = 0;
}
}
void Init_Timer0(void)
{
TMOD |= 0x01;
TH0 = (65536-100)/256
TL0 = (65536-100)%256;
IE_bit.ET0 = 1;
IE_bit.EA = 1;
TCON_bit.TR0 = 1;
}
#pragma vector = timer0
__interrupt void Int_Timer0(void)
{
TCON_bit.TF0 = 0;
TH0 = (65536-100)/256;
TL0 = (65536-100)%256;
count++;
}
I2C介面
Lab10: 外部ROM的讀寫
I2C串列匯流排的組成及工作原理
80
 常用的串列擴展匯流排有:
I2C (Inter IC Bus)匯流排、單總線(1-Wire Bus)、SPI(Serial Peripheral Interface)
匯流排及Microwire/PLUS等。
 I2C匯流排是PHLIPS公司推出的一種串列匯流排。
MCU SRAM ADC DAC RTC
I2C匯流排的資料傳送格式 (I)
81
 資料位元的有效性規定:I2C傳送資料時
 起始和終止訊號(都由主機發出)
void I2C_Start(void)
{
SDA = HIGH;
delay_time(I2CDELAY);
SCL = HIGH;
delay_time(I2CDELAY);
SDA = LOW;
delay_time(I2CDELAY);
}
void I2C_Stop(void)
{
SDA = LOW;
delay_time(I2CDELAY);
SCL = HIGH;
delay_time(I2CDELAY);
SDA = HIGH;
delay_time(I2CDELAY);
}
I2C匯流排的資料傳送格式 (II)
82
• 位元組傳送與應答(Response/Acknowledgement (ACK))
   
uint8 i2c_write(uint8 output_data)
{
uint8 index;
// Send 8-bits data
for(index = 0; index < 8; index++)
{
// check MSB and send it on SDA
if(output_data & 0x80)
SDA = 1;
else
SDA = 0;
delay_time(I2CDELAY); // For signal stable
// Move 2nd-bit to MSB
output_data <<= 1;
SCL = HIGH;
delay_time(I2CDELAY);
SCL = LOW;
delay_time(I2CDELAY);
}
I2C匯流排的資料傳送格式 (III)
   
/* ACK */
SDA = HIGH; // Master make ACK = 1
delay_time(I2CDELAY);
SCL = HIGH;
delay_time(I2CDELAY);
if (SDA == 0) { // Slave make ACK = 0 (YES)
SCL = LOW;
delay_time(I2CDELAY);
return(1); // ACK YES
}else{
SCL = LOW;
delay_time(I2CDELAY);
return(0); // ACK NO Response
}
}
83
Initial after Start: SDA=0, SCL=1
訊號的時序要求
84
4.7 μs
4 μs
4.7 μs
4 μs
4 μs 4 μs
I2C匯流排的數據框架格式
85
匯流排一次資料傳送的組合方式
86
A. 主機向從機發送資料,資料傳送方向在整個傳送過程
中不變:
B. 主機在第一個位元組後,立即從從機讀數據
C. 在傳送過程中,當需要改變傳送方向時,起始訊號和
從機位址都被重複產生一次,但兩次讀/寫方向位正
好反相。
S
Slave
Addr.
0 A Data A Data A/A P
S
Slave
Addr.
1 A Data A Data A P
S
Slave
Addr.
0 A Data A/A S
Slave
Addr.
1 A Data A P
使用I2C介面的周邊裝置
87
AT24C01:128位元組(128×8-bits)
AT24C02:256位元組(256×8-bits)
AT24C04:512位元組(512×8-bits)
AT24C08:1K位元組 (1K×8-bits)
AT24C16:2K位元組 (2K×8-bits)
Atmel的AT24C系列
MCU EEPROM RAM I/O Exp RTC
AT24C02 PCF8570 PCF8574 DS1337C
寫入ROM的步驟
88
S
Slave
Addr.
0 A
Register
Addr.
A Data1 A … Data_n A P
從ROM讀取資料的步驟
89
S
Slave
Addr.
0 A
Register
Addr.
A
Slave
Addr | 0x01
A … Data_n A P
實習10
90
 練習1:撰寫I2C驅動程式並測試ROM的讀寫
 練習2:寫滿ROM,再讀出所有內容以控制LED亮滅
/*******************************************************
Filename: exercise10-01.c
Description: I2C demo
********************************************************/
#include<ioAT89C52.h>
typedef unsigned char uint8;
#define SDA P2_bit.P2_0
#define SCL P2_bit.P2_1
#define I2CDELAY 10
#define HIGH 1
#define LOW 0
void I2C_Init(void);
void I2C_Start(void);
void I2C_Stop(void);
uint8 I2C_WriteByte(uint8 output_data);
uint8 I2C_ReadByte(uint8 send_ack);
void I2C_Write(uint8 I2C_Addr, uint8 Reg_Addr, uint8 Reg_Data);
uint8 I2C_Read(uint8 I2C_Addr, uint8 Reg_Addr);
void delay_time(uint8 delay);
void delayms(uint8 time);
void main()
{
uint8 a;
I2C_Init();
I2C_Write(0xA0, 23, 0xAA);
delayms(1);
a=I2C_Read(0xA0, 23);
P1 = a;
while(1)
{
P1 = a;
}
}
91
/**********************************************
* @fn I2C_Start
* @brief Start to use the I2C Bus.
* ____1____
SCL: XXXXXX_| |_______
____1___
SDA: XX_| |____0_____
* @param None
* @return None
*********************************************/
void I2C_Start(void)
{
SDA = HIGH;
delay_time(I2CDELAY);
SCL = HIGH;
delay_time(I2CDELAY);
SDA = LOW;
delay_time(I2CDELAY);
}
/**********************************************
* @fn I2C_Stop
* @brief Stop using the I2C Bus.
* __________
SCL: _XXXXX___|
______ ______
SDA: XXXX |______|
* @param None
* @return None
**********************************************/
void I2C_Stop(void)
{
SDA = LOW;
delay_time(I2CDELAY);
SCL = HIGH;
delay_time(I2CDELAY);
SDA = HIGH;
delay_time(I2CDELAY);
}
/*******************************************
* @fn I2C_Init
* @brief Initialize the I2C Bus.
* @param None
* @return None
*******************************************/
void I2C_Init(void) // SDA = 1, SCL = 1
{
SDA = HIGH;
delay_time(I2CDELAY);
SCL = HIGH;
delay_time(I2CDELAY);
}
/*************************************************************************************
* @fn I2C_WriteByte
* @brief Write 1-byte data to the bus.
* _ _ _ _ _ _
SCL: |_| |_| |_| |_| |_| |_| |__
SDA: DDDDDDDDDDDDDDDDDDDDDD
* @param output_data: The data byte to write on the bus (include R/W bit as D0!)
* @return Response (ACK, acknowledgement)
************************************************************************************/
uint8 I2C_WriteByte(uint8 output_data)
{
uint8 index;
/*---- Begin to send 8-bits data to the bus ----*/
for(index = 0; index < 8; index++)
{
// The last step of I2C_Start() is SCL = HIGH
// The end of this loop is also SCL = HIGH,
// thus the loop is started with SCL = LOW to toggle the clock
SCL = LOW;
delay_time(I2CDELAY);
if(output_data & 0x80) // Check MSB bit
SDA = 1;
else
SDA = 0;
delay_time(I2CDELAY);
output_data <<= 1; // shift the data 1-bit left
SCL = HIGH;
delay_time(I2CDELAY);
}
// The end of above loop is SCL = HIGH
// Thus, here SCL should toggle to LOW
SCL = LOW;
delay_time(I2CDELAY);
/*---- End of sending 8-bits data to the bus ----*/
/*---- Begin to check ACK response ----*/
SDA = HIGH; // SDA = HIGH for Slave
delay_time(I2CDELAY); // to pull it LOW
SCL = HIGH; // Toggle SCL to HIGH
delay_time(I2CDELAY);
if (SDA == 0) { // Slave return ACK bit
SCL = LOW; // Toggle SCL to LOW
delay_time(I2CDELAY);
return(1); // ACK YES
}else{ // Slave return NO ACK bit
SCL = LOW; // Toggle SCL to LOW
delay_time(I2CDELAY);
return(0); // ACK NO
}
/*---- End of checking ACK response ----*/
}
92
93
/*************************************************************************************
* @fn I2C_ReadByte
* @brief Read data from the bus.
* _ _ _ _ _ _
SCL: |_| |_| |_| |_| |_| |_| |__
____________ _____
SDA: |xxx_|
* @param send_ack = 0: No ACK send / send_ack = 1: Send ACK to end data transfer
* @return The read-in data byte
************************************************************************************/
uint8 I2C_ReadByte(uint8 send_ack)
{
uint8 index;
uint8 input_data = 0x00; // Creat a new variable for reading 1-byte data in
// Before reading data, writing address to the bus must be done first.
// The last step of I2C_WriteByte() is SCL = LOW and SDA = HIGH/LOW
// No matter what SDA is, just make it HIGH to get the bus ready
SDA = HIGH;
delay_time(I2CDELAY);
/*---- Begin to read 8-bits data from the bus ----*/
for(index = 0; index < 8; index++) { // 8-bits, Read MSB first
input_data <<= 1; // shift the data 1-bit left
SCL = HIGH; // Toggle SCL to HIGH
delay_time(I2CDELAY);
input_data = input_data | SDA; // Put the read-in bit at LSB
SCL = LOW; // Toggle SCL to LOW
delay_time(I2CDELAY);
}
/*---- End of reading 8-bits data from the bus ----*/
/*---- Begin to return ACK response ----*/
if (send_ack)
SDA = LOW; // ACK on SDA goes LOW if required
else
SDA = HIGH; // otherwise, goes HIGH
/*---- End of returning ACK response ----*/
delay_time(I2CDELAY);
SCL = HIGH;
delay_time(I2CDELAY);
SCL = LOW;
// delay_time(I2CDELAY);
// SDA = HIGH;
// delay_time(I2CDELAY);
return(input_data);
}
/***************************************************************************************************
* @fn I2C_Write
* @brief Write data to the register on a specific device.
* (1) Addressing the device
* (2) Addressing the register on that device
* (3) Writing data to that register
* @param I2C_Addr: Slave device address, Reg_Addr: Regiter address, Reg_Data: Data to write-to
* @return None
***************************************************************************************************/
void I2C_Write(uint8 I2C_Addr, uint8 Reg_Addr, uint8 Reg_Data)
{
I2C_Start(); // Start bit
I2C_WriteByte(I2C_Addr); // Slave Address
I2C_WriteByte(Reg_Addr); // Register Address
I2C_WriteByte(Reg_Data); // Register Data
I2C_Stop(); // Stop bit
} /****************************************************************************************
* @fn I2C_Read
* @brief Read data from the register on a specific device.
* @param I2C_Addr: Slave device address, Reg_Addr: Regiter address
* @return Reg_Data: Data to read-in
****************************************************************************************/
uint8 I2C_Read(uint8 I2C_Addr, uint8 Reg_Addr)
{
uint8 Data;
I2C_Start();
I2C_WriteByte(I2C_Addr); // Slave Address
I2C_WriteByte(Reg_Addr); // Locate the register address to read
I2C_Stop(); // Stop bit
I2C_Start();
I2C_Addr = I2C_Addr | 0x01; // Device Address uses 7-bits (A7~A1), A0=1=Read
I2C_WriteByte(I2C_Addr); // Locate the address to read
Data = I2C_ReadByte(0); // Read data and send ACK to end up the transfer
I2C_Stop(); // Stop bit
return(Data);
}
94
95
/**************************************************************************************
* @fn delay_time
* @brief simple delay with a NOP loop
* @param time = 0 ~ 255, the delay time be be around few tens to hundred of us.
* @return None
************************************************************************************/
void delay_time(uint8 delay)
{
uint8 i;
for(i=0; i<delay; i++) { ; }
}
/*************************************************************************************
* @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 --;
}
}
練習2: 寫滿ROM再讀出
96
void main()
{
uint8 i;
uint8 ROM_addr=0x00;
I2C_Init();
for(i=0;i<255;i++){
I2C_Write(0xA0, i, (255-i));
}
while(1)
{
while(ROM_addr!=255){
P1=I2C_Read(0xA0, ROM_addr);
ROM_addr++;
delayms(255);
delayms(255);
}
P1=I2C_Read(0xA0, ROM_addr);
}
}

More Related Content

PDF
[嵌入式系統] MCS-51 實驗 - 使用 IAR (3)
PDF
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
PDF
[嵌入式系統] 嵌入式系統進階
PDF
.NET Core 3.0時代のメモリ管理
PDF
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
PDF
C++の話(本当にあった怖い話)
PDF
会社でClojure使ってみて分かったこと
PDF
いまさら聞けないNGINXコンフィグ_F5-NGINX-Community-20200805
[嵌入式系統] MCS-51 實驗 - 使用 IAR (3)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
[嵌入式系統] 嵌入式系統進階
.NET Core 3.0時代のメモリ管理
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
C++の話(本当にあった怖い話)
会社でClojure使ってみて分かったこと
いまさら聞けないNGINXコンフィグ_F5-NGINX-Community-20200805

What's hot (20)

PDF
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
PDF
Constraint Motion Planning について
PDF
LLVM最適化のこつ
PDF
Linuxカーネルを読んで改めて知るプロセスとスレッドの違い
PDF
私のファミコンのfpsは530000です。もちろんフルパワーで(以下略
PDF
低スペックPCでも動く!UE4の設定&歩き方
PDF
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
PDF
Internet Week 2019:D2-3 攻撃者をあぶり出せ!! プロアクティブなセキュリティアプローチ
PDF
【Unite Tokyo 2018】誘導ミサイル完全マスター
PPTX
SLAM技術分享 (輪型機器人的移動議題)
PDF
ネットワークOS野郎 ~ インフラ野郎Night 20160414
PPTX
The TCP/IP Stack in the Linux Kernel
PPTX
x86x64 SSE4.2 POPCNT
PPTX
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
PDF
【2000行弱!】x86用自作カーネルの紹介
PDF
12 分くらいで知るLuaVM
PDF
Kernel crashdump
PPTX
iostat await svctm の 見かた、考え方
PDF
HKG15-311: OP-TEE for Beginners and Porting Review
PDF
C++ マルチスレッドプログラミング
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
Constraint Motion Planning について
LLVM最適化のこつ
Linuxカーネルを読んで改めて知るプロセスとスレッドの違い
私のファミコンのfpsは530000です。もちろんフルパワーで(以下略
低スペックPCでも動く!UE4の設定&歩き方
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
Internet Week 2019:D2-3 攻撃者をあぶり出せ!! プロアクティブなセキュリティアプローチ
【Unite Tokyo 2018】誘導ミサイル完全マスター
SLAM技術分享 (輪型機器人的移動議題)
ネットワークOS野郎 ~ インフラ野郎Night 20160414
The TCP/IP Stack in the Linux Kernel
x86x64 SSE4.2 POPCNT
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
【2000行弱!】x86用自作カーネルの紹介
12 分くらいで知るLuaVM
Kernel crashdump
iostat await svctm の 見かた、考え方
HKG15-311: OP-TEE for Beginners and Porting Review
C++ マルチスレッドプログラミング
Ad

Viewers also liked (20)

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

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

PDF
Arduino: Analog I/O
PPTX
5th unit embedded system and iot design timer and controller
PDF
Introduction to Embedded C for 8051 and Implementation of Timer and Interrupt...
PPT
UNIT-5.ppt
PDF
Arduino: Intro and Digital I/O
PPTX
R tist
PDF
Project single cyclemips processor_verilog
PDF
waveform generation of microcontroller 8051
PPTX
8051 C Assignments with all examples covered
PPT
lecture 12 counter_microcontroller2.ppt
PPTX
pic microcontroller unit 5 detailed .pptx
PPT
8 interrupt 8051
PPTX
Temperature sensor with a led matrix display (arduino controlled)
PDF
timers.pdf
PDF
SSlang: A Sparse Synchronous Language for Hard Real-Time Tasks
PPTX
LCD testtesttesttesttesttesttesttesttest
PDF
Timers and Endge-aligned PWM
PPT
4.Timer_1.ppt
PPT
8051 ch9
DOCX
m.tech esd lab manual for record
Arduino: Analog I/O
5th unit embedded system and iot design timer and controller
Introduction to Embedded C for 8051 and Implementation of Timer and Interrupt...
UNIT-5.ppt
Arduino: Intro and Digital I/O
R tist
Project single cyclemips processor_verilog
waveform generation of microcontroller 8051
8051 C Assignments with all examples covered
lecture 12 counter_microcontroller2.ppt
pic microcontroller unit 5 detailed .pptx
8 interrupt 8051
Temperature sensor with a led matrix display (arduino controlled)
timers.pdf
SSlang: A Sparse Synchronous Language for Hard Real-Time Tasks
LCD testtesttesttesttesttesttesttesttest
Timers and Endge-aligned PWM
4.Timer_1.ppt
8051 ch9
m.tech esd lab manual for record

More from Simen Li (13)

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

Recently uploaded (20)

PDF
Mitigating Risks through Effective Management for Enhancing Organizational Pe...
PDF
PRIZ Academy - 9 Windows Thinking Where to Invest Today to Win Tomorrow.pdf
PPTX
MCN 401 KTU-2019-PPE KITS-MODULE 2.pptx
PDF
Automation-in-Manufacturing-Chapter-Introduction.pdf
PDF
Model Code of Practice - Construction Work - 21102022 .pdf
PDF
Operating System & Kernel Study Guide-1 - converted.pdf
PPTX
Internet of Things (IOT) - A guide to understanding
PPTX
KTU 2019 -S7-MCN 401 MODULE 2-VINAY.pptx
PPTX
CYBER-CRIMES AND SECURITY A guide to understanding
PPTX
Sustainable Sites - Green Building Construction
DOCX
573137875-Attendance-Management-System-original
PDF
Enhancing Cyber Defense Against Zero-Day Attacks using Ensemble Neural Networks
PPTX
MET 305 2019 SCHEME MODULE 2 COMPLETE.pptx
PPTX
additive manufacturing of ss316l using mig welding
PPTX
CARTOGRAPHY AND GEOINFORMATION VISUALIZATION chapter1 NPTE (2).pptx
PPT
Mechanical Engineering MATERIALS Selection
PDF
R24 SURVEYING LAB MANUAL for civil enggi
PPTX
Foundation to blockchain - A guide to Blockchain Tech
PDF
keyrequirementskkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
PDF
Well-logging-methods_new................
Mitigating Risks through Effective Management for Enhancing Organizational Pe...
PRIZ Academy - 9 Windows Thinking Where to Invest Today to Win Tomorrow.pdf
MCN 401 KTU-2019-PPE KITS-MODULE 2.pptx
Automation-in-Manufacturing-Chapter-Introduction.pdf
Model Code of Practice - Construction Work - 21102022 .pdf
Operating System & Kernel Study Guide-1 - converted.pdf
Internet of Things (IOT) - A guide to understanding
KTU 2019 -S7-MCN 401 MODULE 2-VINAY.pptx
CYBER-CRIMES AND SECURITY A guide to understanding
Sustainable Sites - Green Building Construction
573137875-Attendance-Management-System-original
Enhancing Cyber Defense Against Zero-Day Attacks using Ensemble Neural Networks
MET 305 2019 SCHEME MODULE 2 COMPLETE.pptx
additive manufacturing of ss316l using mig welding
CARTOGRAPHY AND GEOINFORMATION VISUALIZATION chapter1 NPTE (2).pptx
Mechanical Engineering MATERIALS Selection
R24 SURVEYING LAB MANUAL for civil enggi
Foundation to blockchain - A guide to Blockchain Tech
keyrequirementskkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
Well-logging-methods_new................

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