01. IIC简介
( @0 \7 G. ^1 U- X$ N8 ?' V& yIIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。2 c3 O1 k3 U L" F
: @! c4 f4 g" s* u( x& qI2C 总线在传送数据过程**有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。) a0 q( f, h7 ~/ H' k
8 S. I }/ {! G7 q6 H# e
开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。
) |/ t4 U' W" A' K. W结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。
* G' n% w- [8 h. l3 s3 z应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。/ B% y) J0 L3 j e* `7 n
6 I$ ?$ B( A' i- x. a/ P
02. 功能描述
: g* J* T! e% u, d" G. g开机的时候先检测24C02是否存在,然后在主循环里面检测两个按键,其中 1 个按键(KEY1)用来执行写入 24C02 的操作,另外一个按键(KEY0)用来执行读出操作,在 TFTLCD 模块上显示相关信息。同时用 DS0 提示程序正在运行。
3 U9 ^0 B- H9 ~# T/ B& ]; ?% ~. k4 b; D0 f- m- |; r; w
03. 硬件模块7 a$ I& ?' ?5 h8 V, E; M
硬件资源有:% J4 E& |8 D, b' F
1) 指示灯 DS0
6 C9 y7 H* \$ N; ?% R; H N0 i2) KEY_UP 和 KEY1 按键
2 q7 [# o) z% K; t3) 串口(USMART 使用)
6 |8 q% d- t' e+ P( q t4) TFTLCD 模块( g; K% C6 x) ^
5) 24C024 f6 G1 ^% O/ _( g* ^ s8 Z
" e0 ] `: y5 C" R# A9 S
1 _$ h" m( v" X' V! z7 X5 I& e8 U3 N9 H
04. 软件设计8 `4 m4 [% R A7 K! _: h
myiic.h
! Q. T# @ a1 l- N- #ifndef __MYIIC_H
! ]& T' o' H6 w6 O - #define __MYIIC_H, a! J" `0 y( F4 [, O8 A- n% E2 K
- #include "sys.h"
8 {! O! j6 d: l8 ?( K8 g -
* V; ]5 e, X) [1 m - //IO方向设置& T# |, E ?1 `; _
- #define SDA_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;} //PB9输入模式% r- e3 |9 C4 L( W; y. {/ j
- #define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //
, O, w) A+ F9 @# e* b `6 _ Z - 0 d4 o( ]0 v( d- s) F
- //IO操作函数 + [* v" d) c, l9 v4 f8 u
- #define IIC_SCL PBout(8) //SCL4 D( N; [7 \# w$ b9 N7 |% W" Z2 s2 I# N
- #define IIC_SDA PBout(9) //SDA 9 o+ m* R( u+ \8 \+ k8 ~3 x# ^
- #define READ_SDA PBin(9) //输入SDA
. U$ U. d2 \5 l7 q5 R/ w7 ?) z - 9 r0 Q% k5 S4 [2 A
- //IIC所有操作函数( F2 ]% e) }4 \5 s' j3 Z
- void IIC_Init(void); //初始化IIC的IO口 : V/ t+ T8 O+ M+ O
- void IIC_Start(void); //发送IIC开始信号
4 K7 V1 }) N; B: {" I( w% U# [ - void IIC_Stop(void); //发送IIC停止信号" s* a/ s' T% z8 S
- void IIC_Send_Byte(u8 txd); //IIC发送一个字节* Q( P$ x6 x: {% m4 P" O2 C9 I, z
- u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节, M3 G! D) o% ~9 {" \
- u8 IIC_Wait_Ack(void); //IIC等待ACK信号
- h4 ~9 a& m6 H% N - void IIC_Ack(void); //IIC发送ACK信号+ \' [8 x6 L- e$ j3 ]5 {
- void IIC_NAck(void); //IIC不发送ACK信号2 p+ L" T1 Y, K- Q ?
- * H6 }% @! H i% T% H& D& f
- void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
8 ~2 V0 x& z6 M" n6 Y5 Q - u8 IIC_Read_One_Byte(u8 daddr,u8 addr);
, O8 u9 h% G9 x& ?, } - #endif
复制代码
/ z& c% R; c# H, O: w$ P0 D7 Nmyiic.c
: |0 D1 u% U3 W7 p9 K1 r; V! M# O: Y9 @7 o$ C2 r: d4 D
- #include "myiic.h"
$ _1 J# N: @; r; l. {4 ]+ e7 I* i/ Y - #include "delay.h"
$ x A1 L9 _- \6 ^: G) H& Q( f
6 t0 m/ ^- r1 w& Y: E- //初始化IIC3 O9 Q, ~& a( T
- void IIC_Init(void)
: l' ^! N b- i# i5 j7 p - { 9 Z8 Y& b1 u" V8 G# T; ?/ E
- GPIO_InitTypeDef GPIO_InitStructure;5 J" M( j% z, R) g
2 h# |5 s# g& A' F9 N- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
: E4 l$ \0 L f3 H1 u- K! d
' K0 T0 k* T4 \+ T2 t1 b- //GPIOB8,B9初始化设置
* y) G! J+ Q% E5 [ - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;0 w. \* [$ C4 [( {
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
. C/ {7 f, n7 I6 c! }! v8 m# V9 y - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
( u. L6 a V7 d- Q5 j# U - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
3 F9 X+ V# |5 P5 c - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉" k9 C, _2 \7 \7 b! ?4 n: k- q
- GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化! ~3 b U! j/ e% I9 b2 q
- IIC_SCL=1;; H" v! e/ |/ b5 W; k0 Q- e
- IIC_SDA=1;
F e6 _* u2 }% a) z" A# O2 h% i - }; ^/ q( l. ?2 Z: R% h
- //产生IIC起始信号
3 U; W( C# O6 n& l: A! v - void IIC_Start(void)
/ E7 o' m" c, ~- I - {
- H s) S& D3 x/ Y - SDA_OUT(); //sda线输出
7 l/ t7 G( I5 J8 O - IIC_SDA=1; , @+ G0 `0 Y% Q. _& h
- IIC_SCL=1;' w9 m0 C9 t& b; l/ r# A) |
- delay_us(4);
+ Y3 `5 U$ ?: S: K$ S - IIC_SDA=0;//START:when CLK is high,DATA change form high to low
9 R4 O! k3 E* N - delay_us(4);
" u; Q1 F B: I) o9 Z7 Z8 d - IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
1 z7 H( b5 J: t: { - }
/ C- F3 o7 X0 \ - //产生IIC停止信号
' q# U; I/ M3 N W, D - void IIC_Stop(void)
. l# t$ Z1 }4 y! V; S6 V9 F! z - {
6 O7 U/ Q2 y9 X1 H5 k+ u, ^, H. ^ - SDA_OUT();//sda线输出6 h6 e1 W) y# R- |. p) d6 i
- IIC_SCL=0;
8 s* _7 V+ u" R9 |. `( B( ` - IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
3 W) d; }, d: q - delay_us(4);& f7 X6 _; W$ m( w9 S% W+ B
- IIC_SCL=1; ; Q# Y6 Q N5 ]5 Q
- IIC_SDA=1;//发送I2C总线结束信号
0 @$ ]5 k# U* n& Q4 ]) z1 G' K1 R5 f - delay_us(4);
! q6 [) e9 N" S! I - }
" s8 e l5 X: K& z - //等待应答信号到来: f3 B, j8 a1 m3 e
- //返回值:1,接收应答失败
! A. k9 K1 y9 M/ D$ Q9 i - // 0,接收应答成功
9 W: j; E7 A1 V5 `6 c$ j - u8 IIC_Wait_Ack(void)7 M, C6 e7 n1 c0 Z3 r$ C
- {0 I" Y3 h( S- C% }6 t/ W
- u8 ucErrTime=0;
" Z! o. V. z9 j! h# s - SDA_IN(); //SDA设置为输入
0 ]! d' f( F1 Q$ ~ - IIC_SDA=1;delay_us(1); % T9 i* h4 k. E( E! ?: X! I
- IIC_SCL=1;delay_us(1);
' @+ E0 I$ C a - while(READ_SDA)
) }0 o) _* o+ i d# R8 _ - {
, J2 S, b V1 s" h# ~$ m5 v- K - ucErrTime++;
5 i, y6 G; O( S! [! l1 U - if(ucErrTime>250)1 f# M/ k0 g/ {' B s
- {
# d1 E4 T9 p3 O: B - IIC_Stop();
. x; L0 K( Q5 ?5 ` - return 1;
/ [7 `! Z6 l; d9 M7 T B! D/ C - }) m) d6 ]+ l. L1 N8 R
- }. w1 w2 U6 B. E7 c8 v
- IIC_SCL=0;//时钟输出0
8 L: }3 E- P( M; d4 K - return 0;
+ B3 f; ]: M% g - } 5 v& }8 [4 B' Z7 ^7 I
- //产生ACK应答
) O( _3 m+ `+ {3 \8 M! G" W& L - void IIC_Ack(void)* n3 q( ~& M9 W' k1 s( r+ h# j8 k+ V
- {
9 Q' _4 G2 a. U' D3 G2 r7 _1 H - IIC_SCL=0;
- Y' {! I6 h9 I( g, L - SDA_OUT();0 A& T4 r- k% _+ H6 R# d
- IIC_SDA=0;
+ V, D9 Y' l/ ?3 @4 [4 A: Q - delay_us(2);
) I* a6 _9 x2 U3 Y; e: \" {; Y - IIC_SCL=1;
' k8 C, I6 Q& B; {" L( b - delay_us(2);
( w. S1 c. x, T# b - IIC_SCL=0;: J1 h+ M! z- K- S c# q7 N E a# V
- }) a1 s; {9 y" w+ }' a
- //不产生ACK应答 1 d, X) p2 k+ R6 [0 ?, J5 d# S
- void IIC_NAck(void)
( n6 A; j% U0 k I& a. I, c - {! I ~1 [8 W; f( ^. j( P# x
- IIC_SCL=0;
/ R! O. J4 s$ J3 E* H5 O& y% F - SDA_OUT();6 j! c: |7 r/ x
- IIC_SDA=1;
( m; k) J) K1 {$ c5 d/ l* K) a - delay_us(2);2 v' l7 F9 j' N' x; W
- IIC_SCL=1;3 m E- Z! N) Y. O; P
- delay_us(2);
- t z4 H+ o1 q+ ^1 C( j8 L! m - IIC_SCL=0;
+ }4 u1 U0 e! e- C8 R/ T& R8 k2 O - } " a* q& L* V( T7 A( G
- //IIC发送一个字节
8 L2 ]0 a2 z3 C - //返回从机有无应答) a c% P ~% [) t: ~* l
- //1,有应答2 A* b- W' E" z, X! Y$ T
- //0,无应答 - r) ^% S1 p$ l2 l) j5 O
- void IIC_Send_Byte(u8 txd)9 V' L8 ~& ~+ [$ a; S
- {
% B3 X. V0 h/ j3 l+ P. `+ ` - u8 t;
9 b8 e4 O( p. q9 V m - SDA_OUT(); 9 u* M' d i6 @' x: m, J& J
- IIC_SCL=0;//拉低时钟开始数据传输
, M3 l- M, Z4 V1 @# |! }8 o - for(t=0;t<8;t++)
8 }$ }) g0 s$ u" P$ l - { 6 d7 g* f) R4 q
- IIC_SDA=(txd&0x80)>>7;6 L4 g. L: `" G4 [
- txd<<=1;
5 V! E; a6 Y! R& ^2 G - delay_us(2); //对TEA5767这三个延时都是必须的
' z1 a" N. v# p9 u - IIC_SCL=1;4 T% v3 S( c' V; W
- delay_us(2);
3 P1 @1 X" M; J5 C5 d9 u( z - IIC_SCL=0;
, U) k- Y1 t) w - delay_us(2);
% X! e+ o6 M; V; X" G: \7 U - } / j0 q; M# S' `; J6 n5 M* k6 w
- } 7 i/ _" O1 L7 @1 v) {6 F
- //读1个字节,ack=1时,发送ACK,ack=0,发送nACK 1 U- Z; N) z1 w7 c! |0 {% P+ \/ |
- u8 IIC_Read_Byte(unsigned char ack)
+ q/ B0 S/ a& S# Q1 N3 A - {7 N; `8 ?. r8 a4 H
- unsigned char i,receive=0;% m: v! f% P. a; i4 E6 I, c
- SDA_IN();//SDA设置为输入
- S6 p7 \! W4 e" g" ]1 e - for(i=0;i<8;i++ ) R {1 n1 {# g; `/ u6 L
- {
' J$ r( E5 I u: _$ a) H- N - IIC_SCL=0;
4 v+ d( e3 R! w0 w3 _+ P$ { - delay_us(2);) j' w" S8 H h3 D! w# H8 D
- IIC_SCL=1;
f$ {# J" `; z8 B/ I! v( y: y - receive<<=1;
1 l5 x! B2 P0 \) h( T/ v9 B C - if(READ_SDA)receive++;
1 L' F; l. l5 b( x' z) G8 B0 j - delay_us(1);
1 \# k c) h' f5 Z4 B6 i) e - } $ \& O& s& ~, k, H0 {0 j7 \! c
- if (!ack)
7 a2 P; h; z' ]# }( e; M - IIC_NAck();//发送nACK
# l" z6 ?2 q# d7 O - else) m7 Y) G4 B9 e
- IIC_Ack(); //发送ACK
/ @, }! u& F) M8 ? - return receive;
( P' B8 h( s# U$ } - }
复制代码 " v$ x, d: f \
main.c
. d( w; ]5 S; L8 Z: x8 T! z5 H, _- #include "sys.h"4 }0 }9 k& u* m
- #include "delay.h"
# Q# }6 d6 c- l - #include "usart.h"
( q0 F: J) T0 U" W - #include "led.h"
' W. _! K( p. G2 W: N- D/ T - #include "beep.h"
& v* t8 B0 L. ~: [8 Y! G! ` - #include "key.h") ?4 M8 E6 K1 p* z# C' C' I
- #include "usmart.h"3 e$ E% T+ O$ u
- #include "lcd.h") U" L! o, B1 A- F/ L d+ m; E$ }. d
- #include "rtc.h"
- t1 C* {, C. i2 I - #include "rng.h"
! u6 d' x4 M0 ?* I6 n- s5 A8 c - #include "key.h"
, f8 f, J& }8 P* P( \ - #include "wkup.h"& h( }, s0 a8 y. [
- #include "adc.h"; t* ?& \- K+ g0 @- s
- #include "dma.h"
; n! N* p/ s l7 f! m& D3 e - #include "24cxx.h"* R5 E$ M+ Y9 y& n$ G% _7 \3 B
- : s' A7 u7 N& m* L) u. e( |- l% W6 |! H5 F- |
V, n& |( h9 b$ W- //要写入到24c02的字符串数组
' `% R) { L8 X1 t6 L - const u8 TEXT_Buffer[]={"Explorer STM32F4 IIC TEST"};
+ Z7 `& Q; j M& Q; x - #define SIZE sizeof(TEXT_Buffer)
" U1 L! ^7 B$ U8 i) b0 [
e2 B6 h, |9 b- v8 e- ! d5 R( L8 H2 I
- int main(void)7 N6 C* i+ e) E1 }+ e3 M6 \
- {
. g5 n' y: @2 b$ P) s q - u8 key;0 d8 i4 f0 \* A, \/ F9 r9 M) c
- u16 i=0;! ]; n6 g4 o7 P4 h
- u8 datatemp[SIZE];
" |9 z. |, a+ }! t) ^3 X - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2& U9 Z/ h: c: _' J6 P- S- E' S, a
- delay_init(168); //初始化延时函数
' c5 d, U) c; Y! d# K - uart_init(115200); //初始化串口波特率为1152000 v" F. {1 Z% o) _7 ?9 N
-
4 e7 ]9 s! j) p6 M3 E% b" _ - LED_Init(); //初始化LED
6 T& x" _/ Y! [" j) c& f+ \6 K( P - LCD_Init(); //LCD初始化
* X8 i% Q4 x, ]* @5 C# v; ] - KEY_Init(); //按键初始化 : l! W0 T) K! [' D) q# |: t
- AT24CXX_Init(); //IIC初始化 5 ?& {+ ]3 U: G# W* N
- POINT_COLOR=RED;
* @) @4 j% |; y# V5 c1 X T - LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");
4 `# w" ? h% g& K - LCD_ShowString(30,70,200,16,16,"IIC TEST");
; t1 q8 ]5 u* [# R8 m( r+ r - LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
, c( C+ i2 k3 O* d" a" H - LCD_ShowString(30,110,200,16,16,"2014/5/6");
8 P0 G* X, r3 d$ p9 Q5 o- s - LCD_ShowString(30,130,200,16,16,"KEY1:Write KEY0:Read"); //显示提示信息
; S* H& |/ w0 d4 c( O7 ]" ]- A* m - while(AT24CXX_Check())//检测不到24c02
2 H( D' N/ Z$ i' X: P - {, A; m9 h a! S% ^* P9 t
- LCD_ShowString(30,150,200,16,16,"24C02 Check Failed!");
) [9 M z5 b7 _# m3 g6 s - delay_ms(500);
! K+ V2 G5 {& n% T - LCD_ShowString(30,150,200,16,16,"Please Check! ");
; J' l! H i& Y1 k: b1 K - delay_ms(500);2 l# M) w. E) w
- LED1=!LED1;//DS0闪烁
& ^! \! j r( b& u1 a& ] - }
7 `3 N% y( C2 N1 [3 ~ - LCD_ShowString(30,150,200,16,16,"24C02 Ready!"); 3 w! V* }1 _1 H% D0 Y4 r$ ?3 \
- POINT_COLOR=BLUE;//设置字体为蓝色 4 T7 V$ d, n7 @0 n
- , j! m/ _8 s% x' V# X q) k
- while(1)
" m/ b9 P5 \$ s+ L- L4 [0 ]* r - {
. e% m* I" [7 B0 o' z- J - key=Key_Scan();2 T: h, a8 X, o5 e) p2 A) x
- if(key==KEY1_PRESS)//KEY1按下,写入24C02
% [* u0 V0 m/ }) O. V - {
& o4 M! ?) y4 p - LCD_Fill(0,170,239,319,WHITE);//清除半屏 : E. W w" t5 g1 b
- LCD_ShowString(30,170,200,16,16,"Start Write 24C02....");
& n7 I& W7 O3 Q9 o j - AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);
, ?2 R* ^2 m) B9 p - LCD_ShowString(30,170,200,16,16,"24C02 Write Finished!");//提示传送完成
, L; d) _. i. h8 @, s! Q' B6 P9 g - }" W; D9 K5 B- ]
- if(key==KEY0_PRESS)//KEY0按下,读取字符串并显示
6 E- [8 B! W' o$ J/ x - {! s4 G; h, C: j- w6 `
- LCD_ShowString(30,170,200,16,16,"Start Read 24C02.... ");
% m: _1 _3 T' D3 t& c - AT24CXX_Read(0,datatemp,SIZE);
2 R0 v& h# F0 Q! Z( j q - LCD_ShowString(30,170,200,16,16,"The Data Readed Is: ");//提示传送完成. S0 ~! w5 `; W7 C7 T3 _- b
- LCD_ShowString(30,190,200,16,16,datatemp);//显示读到的字符串. ]5 W( b, R L+ @7 T5 B
- }
- r$ ?7 [- t3 b% y3 b - i++;
1 X @) e3 w! F( O1 R - delay_ms(10);6 u/ p: u! O* M2 U- v2 j4 }
- if(i==20)! l* K* U# V7 ]9 }
- {% U& o0 S: {6 ?+ J9 M
- LED1=!LED1;//提示系统正在运行
3 Y2 j8 Y$ S+ a. K0 O - i=0;
O! ]( v: p' E" Z2 h; {1 e - }
2 [9 P' {8 @' A, q - } ! Q, @1 j$ w! a
-
3 r: b. v& r' t) Z7 T2 P. x - }
复制代码
# a4 O2 H; _; u1 |1 S/ {; W+ B/ [) T2 e# p. |# ^# S3 d+ a
|
STOP 的时序,好像不对吧