01. IIC简介
, p# w3 N" k) l% W' h1 mIIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。
1 X& V' B; v& R# `1 x# u+ V. A& N: V% _3 S- R" I
I2C 总线在传送数据过程**有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。( t1 U' u3 B+ [* G; Y1 Q8 N
' F# }! x. ~( A$ C7 J: h$ Z
开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。% U* f, H1 Y! A' i! B
结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。, G8 y2 l9 ^: a$ V
应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
8 ]/ X* o6 K! i7 ?8 r7 A. W1 U/ Y7 c2 C
02. 功能描述5 ]* i- W% c* V1 o6 H9 R6 |
开机的时候先检测24C02是否存在,然后在主循环里面检测两个按键,其中 1 个按键(KEY1)用来执行写入 24C02 的操作,另外一个按键(KEY0)用来执行读出操作,在 TFTLCD 模块上显示相关信息。同时用 DS0 提示程序正在运行。
- I$ S6 K% N5 d2 e! S) I
% \8 r0 h* l) T1 a/ L$ P03. 硬件模块
1 l' S8 H# s3 H5 {1 C" m硬件资源有:+ g- i/ I$ ?; |! I; D1 V0 \/ q* z
1) 指示灯 DS0+ o3 U" i% _4 x
2) KEY_UP 和 KEY1 按键8 l7 G4 q1 ~, q
3) 串口(USMART 使用)8 i8 R. T% j% p: N p
4) TFTLCD 模块3 }% f/ t9 v% k! s& I+ H8 g
5) 24C02
+ I1 i6 j' z8 U$ @/ Y6 U& n2 X1 Z& _% J
6 W; ?; D% V4 x2 ~) J
, }- S3 q1 |! p( e6 ]# h- c- h' g/ \# p0 [6 }" e
04. 软件设计1 t+ y2 `8 |3 K! ^- b/ R8 M
myiic.h0 `7 k0 i+ Z# R7 C& _' D7 M5 F
- #ifndef __MYIIC_H9 c# n' I6 M: k/ M$ ^
- #define __MYIIC_H
' Y' m6 B9 }$ L- W B0 f# w - #include "sys.h" 9 e( M- }3 S8 {8 u4 S: d& |
-
$ Y2 s, \) w% R1 i; Y! u7 W( g* A' H. y - //IO方向设置2 h U* `, }2 f/ Z5 J
- #define SDA_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;} //PB9输入模式7 E6 P2 a. r) T, R
- #define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //
% c# v2 X, N, A# \. s" d% Y9 N - 5 C- _: |! n2 _+ ]& k
- //IO操作函数 2 t- i. B6 T S1 |6 h" j
- #define IIC_SCL PBout(8) //SCL2 B4 K7 F2 g: b6 b) U
- #define IIC_SDA PBout(9) //SDA
2 z" I' I7 {9 A8 o/ V) R' g - #define READ_SDA PBin(9) //输入SDA
# I( ]+ N2 E2 c* _& ? - 9 P& y0 s) I) ?. ~
- //IIC所有操作函数
% R3 s9 z: v- I! |! D; K8 ? - void IIC_Init(void); //初始化IIC的IO口
" l, K, W2 F% R# ?" t7 A- p6 e4 B - void IIC_Start(void); //发送IIC开始信号
8 _9 ?# E- U' R; D9 j' y6 Q% I; W - void IIC_Stop(void); //发送IIC停止信号
# u0 Y6 I5 o5 B5 a/ o - void IIC_Send_Byte(u8 txd); //IIC发送一个字节
2 S% E& O. B' F) }; n S( q, C - u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节 `0 T- t" |3 g; o6 X* _- ?' ^
- u8 IIC_Wait_Ack(void); //IIC等待ACK信号7 Z# j2 C; l1 F7 H: K
- void IIC_Ack(void); //IIC发送ACK信号# \! r. p2 T+ o& R& T6 |
- void IIC_NAck(void); //IIC不发送ACK信号# c; L6 w# g4 i# h9 H
- ! a7 F8 x# P1 s4 @
- void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
4 f% [' E/ r% Z# }! u - u8 IIC_Read_One_Byte(u8 daddr,u8 addr);
4 U! y1 }' v+ K! v - #endif
复制代码
, c* a8 q" n N c! Q9 xmyiic.c
" U, w: W) a! U1 F0 R% }8 M9 V! b7 Q' ?* D4 a" }+ f4 h( h
- #include "myiic.h"$ P8 [- ]1 ?: P, |# |* z
- #include "delay.h"
4 g* _. Q0 d# D1 Y - 6 b/ m" u5 w% W0 t% A. S
- //初始化IIC: J, O% B1 q5 ~7 m
- void IIC_Init(void)6 A7 U4 `# J t3 l8 d% z
- {
\1 m4 B2 t9 B: M+ b6 A4 t$ ?; H - GPIO_InitTypeDef GPIO_InitStructure;, W0 _9 w6 e9 O2 Q2 s
- ! p% P' c i, d b! |5 F8 j
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
0 N, b( k6 i3 a. E: X2 U; F
& h% j0 g; b$ D7 D( N8 i- //GPIOB8,B9初始化设置$ h: p4 y# A: Y# C6 m
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
$ ~& V: M5 l2 d/ u - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式' A. ]( v3 P# W1 k# u
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
4 @) k% X C: }0 [: R - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz# U8 _& n: c" B8 _) K8 A
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
8 B4 ~2 q1 _- W! q - GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化- R8 d% p7 X& k* V* x$ m4 a0 M$ g0 b
- IIC_SCL=1;
7 s. p+ H$ H7 L8 {4 G - IIC_SDA=1;
5 x7 F) W% `+ H - }
! x7 b* o' E9 J8 k& l+ P - //产生IIC起始信号
9 s) q7 J5 f! g0 I; B# W2 ]- k - void IIC_Start(void)
/ q; h! S4 q! N2 p$ r0 ^2 ~$ J2 K4 Q - {) A" B) V" q0 q! E$ M
- SDA_OUT(); //sda线输出
* d! B' i, Z& P( ^8 W# K0 u% r3 N - IIC_SDA=1;
8 L2 |; ]7 |7 V0 Y+ {# ]& r2 @ i - IIC_SCL=1;4 J5 a) Q9 V% B1 C- q3 n
- delay_us(4);
1 D# |/ Z6 e+ A1 K' S - IIC_SDA=0;//START:when CLK is high,DATA change form high to low
6 [, X/ ^" j; C( j3 o( } - delay_us(4);+ r# q; {9 ?8 t' R
- IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
0 a3 m' a+ _' f- Y4 X - } ( R. x3 i" W( k( [) U9 G% a8 R$ n6 d
- //产生IIC停止信号/ l' r& L: S, h% h
- void IIC_Stop(void)
- S0 X3 g N0 r. a9 ?4 Q4 ^6 H - {
7 d: p5 ~! Q9 q% x) H; Z, W" D - SDA_OUT();//sda线输出. `: c; O! H* e l2 |( t
- IIC_SCL=0;
5 u/ ?# M# x) j1 Z8 Y - IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
/ @/ k2 f q8 o* L' F0 ^ - delay_us(4);
/ w, F' k; u3 E2 _; ~9 R/ H$ r - IIC_SCL=1;
& h/ I/ e0 e# V - IIC_SDA=1;//发送I2C总线结束信号7 ?# [* R- Q8 d* f7 \% z. b' S% g3 Z
- delay_us(4);
& ]8 P- b2 k9 T ]. O7 V - }
1 G& ~2 q, v! E* j5 i: n* i7 ` - //等待应答信号到来3 U3 }4 r) f$ D. @3 \" P
- //返回值:1,接收应答失败6 C* [+ }; Q5 P6 \9 H4 u$ O
- // 0,接收应答成功5 q$ \' c4 V1 V
- u8 IIC_Wait_Ack(void)
+ u) D) _! P2 t1 y9 f$ r- B* X: D. Q4 d - {0 H. ]- t% n) Z( i% W: O
- u8 ucErrTime=0;
2 C4 J2 L5 z8 t0 S, @% P7 \2 u - SDA_IN(); //SDA设置为输入
0 O2 D; k7 ?5 e# Q6 Q; w - IIC_SDA=1;delay_us(1);
/ c% A' g. d: F6 { - IIC_SCL=1;delay_us(1); ) y ?7 ?- n' z/ _7 ^5 }! z
- while(READ_SDA)% X8 d& q A9 L5 w5 U. m
- {
) x, g" n. P: _" q% F* ~ - ucErrTime++;
; V; W. U& o6 f3 R" ]# @ - if(ucErrTime>250)
. T; Z- g( U9 Z; B& B. O) H - {& A7 Z6 D& f4 d' }3 S
- IIC_Stop();
( j8 x7 g% J' C( c5 A( n3 T - return 1;7 V. K7 O5 \7 b) u6 ^# ]( r
- }. g" ^+ A5 l/ Q, k# @
- }8 t9 p( Z9 y. O% i& O' C/ `$ I4 u3 w
- IIC_SCL=0;//时钟输出0 7 n9 h# t' F) m& I8 a. {6 {
- return 0; 5 F; u9 |, i, H, L9 B5 G) x4 z
- } , `6 \: x- h- t5 o
- //产生ACK应答( b5 i: t/ N) p+ e) i
- void IIC_Ack(void)
2 u; ~: t: \2 i- U# Z2 N( \ - {4 ]/ I2 ~1 V& W1 D" |$ K
- IIC_SCL=0;
6 m( O* Z2 Y( j2 | - SDA_OUT();
5 j6 v* q% m- U7 e - IIC_SDA=0;
2 [: ~+ c4 X' X! e/ H# H: z - delay_us(2);
- J9 b* J( f( x) I; V - IIC_SCL=1;) |7 S' e) c I% p* H V
- delay_us(2);: Z( N/ h: o- U5 ~7 S
- IIC_SCL=0; p0 W" s3 s$ A" X% B
- }( @' i. ?" h7 z; i3 a
- //不产生ACK应答
) a! Q) J2 ~' Z0 R5 i/ h; [ O1 N - void IIC_NAck(void)" c$ J0 i4 N) i% E3 L& l
- {
7 o5 C' O9 J% r4 G - IIC_SCL=0;1 B' j5 W j! e0 V
- SDA_OUT();9 I+ `* z% T/ \: j3 G' ?
- IIC_SDA=1;' G" M9 |0 Y f, a( P+ C
- delay_us(2);
+ A3 N' _1 N- M5 I- T- R - IIC_SCL=1;5 R6 n6 k5 G' K+ w% i6 e8 K
- delay_us(2);, C: N7 E5 \# [- `0 n9 E& B* U
- IIC_SCL=0;
1 @: h; D0 h8 p - } 7 E' T' a! v: m
- //IIC发送一个字节5 ^; v [" a, Z" J- e5 [
- //返回从机有无应答
" {' n, ^7 Q0 f$ C - //1,有应答
$ v+ z1 U& {' X: P - //0,无应答
; C/ |+ S0 A- g - void IIC_Send_Byte(u8 txd): }7 q& W, W5 g' U6 G
- { % u' d1 O4 k8 T) V0 A- b _/ C7 V# k
- u8 t; ' H. _* |4 l% X- n
- SDA_OUT(); 5 ?$ B$ L9 v" y5 W
- IIC_SCL=0;//拉低时钟开始数据传输
2 s0 k" Y) _) p* n - for(t=0;t<8;t++)
4 n* y4 Q6 b/ H7 }6 Q - { ! k4 S" X' B8 }. f/ A
- IIC_SDA=(txd&0x80)>>7;1 g+ Y& ~1 a7 ?% I
- txd<<=1;
, `/ j: X9 o6 n* H9 L - delay_us(2); //对TEA5767这三个延时都是必须的
; M$ O& N2 D) k& B" f - IIC_SCL=1;
6 x: l& R. d: ~, v3 L - delay_us(2);
' y9 I" Z' r3 ~0 y) I2 l& j - IIC_SCL=0;
& s1 k; H! _$ C, R z. |9 n - delay_us(2);9 q: A6 J" M# p3 E+ ]- ~" E& o
- } , c( `8 \; Q& E7 P
- }
+ s! o% ]3 }# y" [9 d# r - //读1个字节,ack=1时,发送ACK,ack=0,发送nACK
$ K) F! }5 E5 S2 l! ~# J6 Y - u8 IIC_Read_Byte(unsigned char ack)
W1 J1 g0 O8 p; \5 I/ L$ O$ A - {
( ]5 ^6 n* S6 u& Q/ m - unsigned char i,receive=0; k$ ]! r; v+ ]' @* m% R* }
- SDA_IN();//SDA设置为输入8 Q1 j- l0 c$ p+ \' Q% z0 k1 s5 B
- for(i=0;i<8;i++ )
# h# C6 R" i/ U: B+ q5 ~& t - {
: M% E; A8 t4 l" O8 ~; Y) g - IIC_SCL=0;
/ x4 q- W9 G$ a0 f0 x4 p, j) v( A - delay_us(2);
% E ~5 k' D2 h9 t! r7 Y - IIC_SCL=1;
: T2 ]; P* }* z, O6 p' J' Y' Z S - receive<<=1;
; d3 w! [, S, W }7 Z - if(READ_SDA)receive++;
8 n0 J* m8 r/ ~ - delay_us(1);
6 e1 f; L/ `5 s; B( } - }
7 a9 ~# y: F7 \) w, m - if (!ack)
% N+ o7 G3 o3 B# W6 Z6 O - IIC_NAck();//发送nACK! |0 [6 J$ x! i8 v* d5 {* w0 K
- else0 I6 p) D5 v# l: Y% u- c' ]. I
- IIC_Ack(); //发送ACK
# G6 Q$ [9 J" K7 X8 w - return receive;
4 o* h* \; E' _6 { - }
复制代码 5 l4 ~' @3 s4 m" B
main.c1 ^; r" c; v8 L, Q7 n) y$ c1 D. r
- #include "sys.h"! M/ q: J3 Y P7 K2 H
- #include "delay.h"9 R: S/ {+ y$ n6 e Z! |9 a
- #include "usart.h"* A( t" N3 g6 x3 Q% ^. \
- #include "led.h"
' K/ \- l# A) U* M h - #include "beep.h"
/ Q8 a: p& ~; j5 ?6 i9 N! t3 i# K$ r - #include "key.h"1 G- ?9 G' P8 E* K
- #include "usmart.h", n, M+ a+ l3 ^4 |- y( X6 x
- #include "lcd.h"
5 C& a! u& h8 o4 Y( |5 w - #include "rtc.h"4 z8 |; C3 I$ E6 W c
- #include "rng.h"
3 L0 H! `6 H5 }% r9 @" t* B - #include "key.h"
- q3 G# b0 L9 p; n5 W( H2 V6 H9 U& U - #include "wkup.h", i+ `7 u5 M! ?8 |* a5 X
- #include "adc.h"2 M: q8 x; [ J/ t6 p
- #include "dma.h"
; K" G) k8 h; y o - #include "24cxx.h"6 x# g. P! ]" O" Y& a; C
8 m0 f1 l% W- m2 t) \+ k- # O# i. R* u1 X3 y3 `6 l
- //要写入到24c02的字符串数组
: @# K# ~4 ]( X3 {9 Q; P5 c - const u8 TEXT_Buffer[]={"Explorer STM32F4 IIC TEST"};$ \! c' l! ]- M3 k U6 f. M; c
- #define SIZE sizeof(TEXT_Buffer)
$ i) p" ~: J' N* \- c) v$ O, V6 w - 4 _1 K& t+ [. c3 ^/ j9 D
% I; p$ a7 g; G' T) }# a3 i- int main(void)
G& D- B: x( z; L - { " @+ F( B% r& R$ G: Z. @
- u8 key;
' X) y ]. L6 o. q - u16 i=0;
' E6 | t, S" }9 v, u9 S% I - u8 datatemp[SIZE]; 2 ^+ w8 m- x3 L/ F3 c
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2! r# e( I3 u- r B) Z2 v
- delay_init(168); //初始化延时函数# Q" T% C: g2 d
- uart_init(115200); //初始化串口波特率为115200
1 L9 s. X7 E% G1 j* V4 Y -
- T" C' r) k S, r$ _ - LED_Init(); //初始化LED
2 n. H% u+ L3 t0 L$ ~7 P& y - LCD_Init(); //LCD初始化 & b* R7 S8 ?0 h5 w0 u9 S
- KEY_Init(); //按键初始化
* V0 L' K% K {8 `. f3 C - AT24CXX_Init(); //IIC初始化
# O# D- Y* O% T1 O& v3 f9 g - POINT_COLOR=RED; ' H1 y/ j6 e1 U. V V8 y9 F
- LCD_ShowString(30,50,200,16,16,"Explorer STM32F4"); 3 Y1 g. C& f& b2 L l
- LCD_ShowString(30,70,200,16,16,"IIC TEST");
" d- {# Z1 }) C" c% A - LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");' \# n4 ~# q: f8 F X
- LCD_ShowString(30,110,200,16,16,"2014/5/6");
" d. C! z4 t# S! U4 ^" A - LCD_ShowString(30,130,200,16,16,"KEY1:Write KEY0:Read"); //显示提示信息 2 h3 J" [, R2 i2 M' }
- while(AT24CXX_Check())//检测不到24c02% U. `1 v! Q" G" u
- {
" Q( m+ @- D& w2 l - LCD_ShowString(30,150,200,16,16,"24C02 Check Failed!");- q, h2 K7 h. e5 ~2 c3 J0 P
- delay_ms(500);
! I! X Y/ R7 F# I# g - LCD_ShowString(30,150,200,16,16,"Please Check! ");
' F8 N+ j& i1 T$ w: b( g( N- H - delay_ms(500);
6 \6 n- r R" b/ \$ Z& d. W9 n - LED1=!LED1;//DS0闪烁
6 E6 R7 L5 ?$ V8 k6 B. q/ J) O - }
: ^, a; F! F6 s! N - LCD_ShowString(30,150,200,16,16,"24C02 Ready!"); 1 q: s* R0 k: J d3 W) Y; {& Y
- POINT_COLOR=BLUE;//设置字体为蓝色
9 q7 E/ k! a* V
1 y. q5 D( s; b4 [$ u- n- while(1)) O% r& @; C( T
- {
7 E* H& g# y% J; K3 p! J j1 ^$ ] - key=Key_Scan();
' R& s- O* h! i& U: C1 @ - if(key==KEY1_PRESS)//KEY1按下,写入24C029 t; {- Z9 ]0 K1 H) S) W
- {
* y) |2 n4 M' z' P# C2 [9 Y, e) H - LCD_Fill(0,170,239,319,WHITE);//清除半屏
8 t/ l7 m% E; D0 k - LCD_ShowString(30,170,200,16,16,"Start Write 24C02....");. v+ q7 E* A( y% j! b# |0 n
- AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE); q( {* Y4 Q- D5 s A
- LCD_ShowString(30,170,200,16,16,"24C02 Write Finished!");//提示传送完成
* U1 X" @1 c* \; L - }
/ X& F% _) f7 F8 E d- \& M! S - if(key==KEY0_PRESS)//KEY0按下,读取字符串并显示
" |( l# @# k. {$ p" K& {/ A+ _ - {' [# [# U. p) F9 U. `
- LCD_ShowString(30,170,200,16,16,"Start Read 24C02.... ");
4 D9 z, U2 l* {+ z - AT24CXX_Read(0,datatemp,SIZE);
6 f+ _ B1 |8 _0 ^3 Y7 T- { - LCD_ShowString(30,170,200,16,16,"The Data Readed Is: ");//提示传送完成: t m1 J! f- G8 @5 V9 J" x- b
- LCD_ShowString(30,190,200,16,16,datatemp);//显示读到的字符串
8 ]. O6 x6 k5 v. t% C - }
9 q5 s9 K0 B0 U/ Q) }3 l - i++;' E+ \! z/ s( b& a
- delay_ms(10);
% n1 ^0 f1 K, _' } o, Y+ ]5 _ - if(i==20)) i- K: Z7 A& C7 K: a& I2 R
- {3 j9 o' h+ s9 g$ {$ O$ i0 _. q
- LED1=!LED1;//提示系统正在运行
: R% k9 M. u s2 ^ - i=0;2 i- E5 ]7 @! q7 P; i
- }
- L+ P- l1 }: N H h5 I& Q - } " L5 l7 ~5 B9 x- R8 A& @- [/ M3 H# `1 g
- 7 h* `5 ]+ K& f O; a: g! U
- }
复制代码
, H; D8 Q; n" E6 V# Q1 _
0 ^$ i3 n' V) Q R |
STOP 的时序,好像不对吧