01. IIC简介" F) [$ W$ O x+ t* Q
IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。
( s+ \: `! e2 ^+ |
6 R' D" d" s6 [( [" I+ OI2C 总线在传送数据过程**有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。1 ]6 p9 M% @' l. k) |6 L+ d& F
- a5 U2 ^/ `+ i A开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。
) G4 Z" U8 h { z x7 i: k/ B- t; N结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。
3 E0 \1 m4 v |; y/ a应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。. O3 j( F i, p" S6 M: I" P0 J3 d- O
, o# \: `- E$ y# i& I( i02. 功能描述8 ` j l O3 P1 k% w: Q
开机的时候先检测24C02是否存在,然后在主循环里面检测两个按键,其中 1 个按键(KEY1)用来执行写入 24C02 的操作,另外一个按键(KEY0)用来执行读出操作,在 TFTLCD 模块上显示相关信息。同时用 DS0 提示程序正在运行。
& z3 C9 x( ~3 i. e9 S$ R1 w7 B0 n- c! T' l
03. 硬件模块6 w. X* o6 l1 U7 i& Q% p
硬件资源有:
# ?9 @, h9 G$ F; A7 [0 E2 A& n1) 指示灯 DS0
0 v6 g3 Y7 x3 L4 K8 l h8 ~. N! c2) KEY_UP 和 KEY1 按键
! f u8 ]! I" Y, C& B: V3) 串口(USMART 使用)4 B) y1 _1 T5 `. x
4) TFTLCD 模块
: R8 @9 n- d' A# N* g5) 24C02# g8 Q3 ^. ?+ z. V* Z1 }! }
& `4 Z. Q/ W6 a# d: z! ?
) c0 u: o: f6 z0 Q- W" k* F
1 V5 k" w) Z. B( d4 ?' d5 @04. 软件设计
. @0 |! n3 E% M8 L4 `* S3 ~8 Z0 lmyiic.h
6 K+ O# [; p$ \# X6 }- #ifndef __MYIIC_H
: K& k4 i4 T6 A$ \5 } - #define __MYIIC_H& ]: y; D) D& z* J
- #include "sys.h" . z$ {8 z+ P3 u- m) N6 p
-
9 m5 \* k) K$ I4 t& f: p - //IO方向设置
2 ~/ G: z9 G3 G; F+ Y# ~ - #define SDA_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;} //PB9输入模式. }4 T7 T1 `7 O- i# ?( }' {
- #define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //
- e, X7 b# Z+ z6 r; ?" A
: q( h! X( ]- D! L" L- //IO操作函数 6 e7 q0 ?) u9 r
- #define IIC_SCL PBout(8) //SCL W2 e4 x9 p! _, U
- #define IIC_SDA PBout(9) //SDA ' ^- G8 U# z9 u$ h8 l1 ?/ S
- #define READ_SDA PBin(9) //输入SDA
3 `1 d3 E8 Z1 Z# a- K - 1 r: X: ?# ^# W* \3 Q. u
- //IIC所有操作函数
2 L, o( C# K" }5 Z - void IIC_Init(void); //初始化IIC的IO口 $ u; S; f, h; D" G5 K% q
- void IIC_Start(void); //发送IIC开始信号
5 c" n3 P% Z9 N2 }: \ C - void IIC_Stop(void); //发送IIC停止信号) `/ j8 W; P8 a- @( o ]. k: o! F
- void IIC_Send_Byte(u8 txd); //IIC发送一个字节9 q9 R M9 r3 G& f. w! a9 A
- u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节- \" h& M+ m# W( M1 x+ ~3 D/ G5 x
- u8 IIC_Wait_Ack(void); //IIC等待ACK信号. }1 K0 }4 e% @
- void IIC_Ack(void); //IIC发送ACK信号/ m% @$ K, z9 `$ U$ ~
- void IIC_NAck(void); //IIC不发送ACK信号9 `$ @) u0 c- w j$ C" A$ B# J
- ' P* H9 h" G0 X. f. b$ w5 n+ s
- void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);3 f4 m6 f1 ^5 Y* p1 C+ F1 D
- u8 IIC_Read_One_Byte(u8 daddr,u8 addr); ! n+ y: j. Z- n
- #endif
复制代码
- @# Y1 A( z' d* d0 Smyiic.c% `/ H) |+ O) V8 y$ @2 N
! t0 T# r4 B9 L8 A9 \4 }. Q+ D- #include "myiic.h"
( V. G f$ g- D8 } - #include "delay.h"6 p5 O( u! H& D& u; A! G+ F: s0 D
/ t0 n: R3 A0 M- //初始化IIC! ?/ s' Z0 c( i4 h
- void IIC_Init(void)
2 }* G# o! A0 b" D" w8 G - { : r6 B8 Z# j, V% o
- GPIO_InitTypeDef GPIO_InitStructure; i7 |- e8 P" n8 F, D6 a" p) A
- . h! ^% v4 U8 Y" N$ S# L, F
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟7 i; ~& N6 ^0 X& [6 p: i( w: L
- 4 C. X4 v3 K+ x9 G
- //GPIOB8,B9初始化设置$ d: S& G2 |0 B
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;8 L' N5 }) @3 s/ ]
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式0 B0 d6 H. ~4 y2 \# [7 J
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
5 p4 T8 M. L0 w" S! b - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
- s% U4 ]) H6 a - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉) J" q* M, ~! S4 J" Q- p
- GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
: _6 ]5 q5 e) Y5 m G' Q( c - IIC_SCL=1;6 o% j4 W z( C* @; s3 U. g
- IIC_SDA=1;
( {8 V! W& ^5 M+ E: J# c' s/ A - }0 ^' p+ |! o/ r0 o5 ~& U
- //产生IIC起始信号
1 g8 \2 i9 X8 \5 Z* W1 W7 j- ] - void IIC_Start(void)
/ Q2 f+ q& R. G - {+ b4 k m/ K' j, ?0 p/ |
- SDA_OUT(); //sda线输出
+ u7 S/ P$ @6 ~7 _' Y - IIC_SDA=1;
) {5 `4 D% n+ ?6 o8 Q* ]- {! w - IIC_SCL=1;, B' _7 O+ E/ O% X& c/ P6 m. s+ R6 P, Y
- delay_us(4);
3 L+ g, o+ I3 w- e, A. J - IIC_SDA=0;//START:when CLK is high,DATA change form high to low
- A' j6 ]% J: r0 Y - delay_us(4);
1 |7 p |! }: V/ i - IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 ( M9 `9 Z, F* B: U
- } . S9 H$ |( S8 A S1 M$ z L
- //产生IIC停止信号4 G5 Y4 \/ q. J4 Z9 S9 o3 P1 W
- void IIC_Stop(void)
) V+ ?" c; A/ X3 Y, I4 X; T- y - {
% c3 {2 o0 Z% p - SDA_OUT();//sda线输出
- X5 b4 S1 {' n - IIC_SCL=0;5 H( ^! D* X( @$ W
- IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
: S5 e$ y9 j7 [0 K - delay_us(4);
: @- P) e& {/ o9 Y$ ~ - IIC_SCL=1; # b7 j: h5 {2 o4 J2 s) g
- IIC_SDA=1;//发送I2C总线结束信号4 b& ?$ N( O- `& E: s
- delay_us(4); 4 ~# O0 Z# l$ o9 d7 W ?2 h) }
- }/ F+ B8 M& x+ e( Z
- //等待应答信号到来7 I/ K0 c# s* \1 S" P
- //返回值:1,接收应答失败
: t( J! d" ]6 W8 S2 Q# ?7 d - // 0,接收应答成功
3 |; s9 V0 m8 O5 [( R - u8 IIC_Wait_Ack(void)
z$ x% k! l/ u% {/ W+ O - {+ S6 H1 R0 f( I; @7 |* f i+ r
- u8 ucErrTime=0;
8 S$ F% L% E5 H; F - SDA_IN(); //SDA设置为输入 0 X& }0 n4 b) n4 [* T# _
- IIC_SDA=1;delay_us(1);
& H: u% \! j3 [ - IIC_SCL=1;delay_us(1);
4 r* y) P9 u0 G f; ]4 h - while(READ_SDA)
$ x! R( J) }0 s4 L$ L2 g% H: t( [ - {
7 m9 H9 Q ?* o1 n/ x - ucErrTime++;
' j0 `( _! d' }& o1 ~2 N5 D E, i# X2 { - if(ucErrTime>250)
9 j. D- l0 o8 y* Z1 Y$ z8 z# ^9 S$ o - {
1 }3 g4 w x8 [2 R. ?$ O - IIC_Stop();
, e, Q+ W/ _/ V8 o - return 1;
2 p9 h- ~* X, F" n3 M: c' ? - }% i; k U( ?: V ^1 O
- } O6 A( a1 n9 @
- IIC_SCL=0;//时钟输出0
0 p4 m1 P# z$ |5 g! H. C - return 0; 8 m d: i! O2 \, i! @
- } % ]7 X1 x8 P0 `
- //产生ACK应答4 q$ V; D' ~; H+ I! O' P
- void IIC_Ack(void)$ X) L) ~" v9 W8 R% U2 W% d8 g
- {
: l0 r, F7 `& L% o1 X4 ? - IIC_SCL=0;$ N: _3 h* c8 E: u& Z+ g% m P
- SDA_OUT();
U1 n! s7 o7 V - IIC_SDA=0;- I$ K, K+ ~ `/ d% E% i
- delay_us(2);4 O1 \9 d9 U7 |4 ~
- IIC_SCL=1;
# c. [: ]( H2 { - delay_us(2);% C; x$ V7 u5 @3 U
- IIC_SCL=0;
1 r9 c, [3 d0 x* W3 J - }( ]8 S2 ]& f5 E
- //不产生ACK应答 7 n! \+ P1 ~8 O/ `0 b+ u
- void IIC_NAck(void)
& z' h( N: V$ x# U0 @8 g - {6 y6 S5 t1 g# c: U
- IIC_SCL=0;7 J) l5 F2 k+ N
- SDA_OUT();
, v5 Y8 z0 X) o - IIC_SDA=1;: y: A& @! o5 M1 [( W
- delay_us(2);7 F0 U: A3 k, W
- IIC_SCL=1;
+ |$ I+ p5 O+ H/ M+ V. R, ^ - delay_us(2);$ I, Z: R. n6 L& W
- IIC_SCL=0;
. s5 C2 q" M, h - }
$ N: R$ [* [3 r" N0 y$ z - //IIC发送一个字节) x( c& N: G: c* d9 |! E' R/ E
- //返回从机有无应答8 L# y" o% x* p) W
- //1,有应答
' `. J7 w3 N; t; T- p - //0,无应答 9 D! q' \9 Z9 f E# M- K8 _: O" M
- void IIC_Send_Byte(u8 txd)
, |) @3 F0 I* _6 [* r. p - { ' K2 j/ C8 Y5 m d1 ?' V8 A+ Z3 f
- u8 t;
7 }2 i8 o( o# n. D) s - SDA_OUT();
! I& u9 c9 w' ^& }. P) i) \6 Q - IIC_SCL=0;//拉低时钟开始数据传输; W H: ~+ X2 p/ A7 p
- for(t=0;t<8;t++). _/ M7 q& a4 |7 m+ W! O8 ]5 o2 u
- {
/ d. p9 j+ C8 E8 d4 K - IIC_SDA=(txd&0x80)>>7;
( C+ z( q: X- C" U: T! W - txd<<=1; 9 T$ u6 \5 T) b1 h# p6 P
- delay_us(2); //对TEA5767这三个延时都是必须的 f% _% v+ o0 Q; a9 c1 S. g4 c3 |
- IIC_SCL=1;3 l/ R& R6 ~, {# G; I D
- delay_us(2); + X; _- Y" p- b% y2 v& j
- IIC_SCL=0; & d, }6 _- K- s' Z, u0 }
- delay_us(2);
4 j" u7 m+ C' G9 o: y, A - }
: z1 a9 x D+ `8 I' O: F: y - } 9 Y+ n( ^# o9 r, l
- //读1个字节,ack=1时,发送ACK,ack=0,发送nACK
* C" |7 u* K& m* ]; @ - u8 IIC_Read_Byte(unsigned char ack)$ X' U$ a" ?/ Z' |* G
- {* y+ ^' o6 `- @' \
- unsigned char i,receive=0;
, a1 A/ `7 Y) I* r. v2 H - SDA_IN();//SDA设置为输入
' O1 z) r4 V% ^5 t. C) a - for(i=0;i<8;i++ )% ~$ a: N: i# f2 o6 T$ u+ `4 ~
- {
, {0 V& g2 i# H8 Q) Y! k - IIC_SCL=0; 4 {. N, f8 b$ Y; X3 N/ k1 {
- delay_us(2);. A7 ~. T4 z2 h# j( U
- IIC_SCL=1;
4 Y5 [5 ]' G6 X3 W* u2 f - receive<<=1; l$ F, x5 A" L. C" i
- if(READ_SDA)receive++;
6 q4 z* N5 T0 c! X2 w - delay_us(1); $ I9 J# c7 c( P# D* T6 `
- } $ n# \; b+ U1 J
- if (!ack)
8 Z; s9 d ^2 p f- [ - IIC_NAck();//发送nACK
' ~8 F" q! U; v# X4 K - else% `. b' h8 i; k* V8 G5 f( d5 C0 y
- IIC_Ack(); //发送ACK
* Q' R4 O E, C$ K5 g8 ?8 v - return receive;$ |) W4 r1 u/ N" j7 y* D. r! r1 Q
- }
复制代码 9 i" ~/ [& H }. v3 f( f
main.c
. W) S# r% u! H2 m6 ~- b$ Q- #include "sys.h"
, o# j6 B$ [1 a! n# @0 z! X9 ] - #include "delay.h"
% {7 i- s2 y8 k7 g# v- `/ G - #include "usart.h"
1 y7 ]; w: l! A) s L6 V7 z - #include "led.h"
+ N1 x) P( t2 ]9 b1 M) ^ - #include "beep.h"0 H8 E7 k# @3 ^" i7 C
- #include "key.h"
( n; C1 R& c" S) C - #include "usmart.h"( U: n2 {/ w0 O( O6 q" y$ \
- #include "lcd.h"
) E% f7 C+ b' t/ p3 g$ ~: } - #include "rtc.h"4 @2 Y! T5 E' U% W
- #include "rng.h"
2 b$ O: w* ^1 x( T& T - #include "key.h"
0 m, j0 j* S, | - #include "wkup.h"- ?! m! i+ Y8 H, p$ t8 r
- #include "adc.h" j4 D) Z' F8 X: y W, l) b- d
- #include "dma.h"' {, p$ p: K; L- J. Y! ]9 Z
- #include "24cxx.h"2 K0 z* j5 v. S' o8 a2 j
4 a$ d8 z( j% r3 q% t8 J- : l! o \, C2 m4 V: |" K/ w
- //要写入到24c02的字符串数组0 n: w z: F4 [( o+ R U% Y
- const u8 TEXT_Buffer[]={"Explorer STM32F4 IIC TEST"};0 a; R. {7 B/ f {3 c
- #define SIZE sizeof(TEXT_Buffer)
/ L2 T8 x( n6 I& o
, Z h: r, ?! n2 ^1 q
* H+ ?7 I2 I' q7 s' {- int main(void)0 T. E- l. Y! A8 T
- { 3 v' V+ }! g& z9 Y2 ?
- u8 key;
7 v% m* j- u+ ~ - u16 i=0;$ f2 L5 A4 ?/ p5 Y5 Z' a Z
- u8 datatemp[SIZE];
7 H8 G! N0 M5 T& w& P( o - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
; t* ~ |8 N. I# e! Y: o - delay_init(168); //初始化延时函数6 B* y9 s3 V* J9 C0 V- G" D. B
- uart_init(115200); //初始化串口波特率为115200. {6 e! b& x. w0 B4 }* p/ e9 I
- / P; P9 V* x' Q) M- K
- LED_Init(); //初始化LED 8 k& S# K2 P) K, o$ C) v) \
- LCD_Init(); //LCD初始化 , h: Q8 `; R& c4 G9 B
- KEY_Init(); //按键初始化 # D" {4 }+ i, o. A0 A
- AT24CXX_Init(); //IIC初始化 2 {7 y- G7 W% \+ K6 ^
- POINT_COLOR=RED;
$ _' E% p8 n" B% @ - LCD_ShowString(30,50,200,16,16,"Explorer STM32F4"); : q+ j7 U4 }# ~( }) k" [
- LCD_ShowString(30,70,200,16,16,"IIC TEST"); 3 E7 h" K3 d1 Q! I3 f
- LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");$ V, R& _ E5 D' N$ l# D1 |
- LCD_ShowString(30,110,200,16,16,"2014/5/6");
* l" V5 W% ]' q - LCD_ShowString(30,130,200,16,16,"KEY1:Write KEY0:Read"); //显示提示信息 % I# W: e2 R: s1 H7 i9 \( ~
- while(AT24CXX_Check())//检测不到24c02, M) G2 ~- K* E6 d3 |# q
- {
N q! S/ |1 S- O( K, e- M - LCD_ShowString(30,150,200,16,16,"24C02 Check Failed!");
0 z" H0 }+ h, N. C - delay_ms(500);
2 `+ a! m8 i( g* l( ]$ t - LCD_ShowString(30,150,200,16,16,"Please Check! ");* t# q$ z5 { N
- delay_ms(500);7 S% v6 R t% b: k6 S3 ?1 e, }$ N
- LED1=!LED1;//DS0闪烁
5 V; {- ]: F A/ x - }
" f& \7 K; O1 v( N( {4 w1 E7 s - LCD_ShowString(30,150,200,16,16,"24C02 Ready!"); 9 O% D" B! ^* M- J' K/ c0 f) V
- POINT_COLOR=BLUE;//设置字体为蓝色 ( a5 n$ l- _) t9 W5 E
- 5 U- X9 [: X0 W; Q4 {
- while(1)! N& X4 A3 s/ }1 `" O3 l; H
- {: p# Y1 h8 b# ^; `- m0 ?
- key=Key_Scan();
$ ^; W/ o: z7 I9 K/ { - if(key==KEY1_PRESS)//KEY1按下,写入24C02
$ m2 q8 I. P. k - {
+ a* R- D( t" [7 {. A - LCD_Fill(0,170,239,319,WHITE);//清除半屏 ! k( B& v( l& g! _
- LCD_ShowString(30,170,200,16,16,"Start Write 24C02....");/ d3 N F9 X. P3 x+ [4 ]
- AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);
8 ?3 R* ^) J2 v* X* W - LCD_ShowString(30,170,200,16,16,"24C02 Write Finished!");//提示传送完成& X( m7 T8 T3 v6 J7 p; X- o
- }3 `0 G$ ]8 `6 Z0 {6 n$ C9 o; x
- if(key==KEY0_PRESS)//KEY0按下,读取字符串并显示
/ g' I- w1 e6 r - {/ H! L8 h8 F' D5 i
- LCD_ShowString(30,170,200,16,16,"Start Read 24C02.... ");5 O( I4 K* S# G r7 E; H
- AT24CXX_Read(0,datatemp,SIZE);
3 ~3 t. G7 G2 y6 l: w) Q - LCD_ShowString(30,170,200,16,16,"The Data Readed Is: ");//提示传送完成4 r( a' Z# K4 n1 [
- LCD_ShowString(30,190,200,16,16,datatemp);//显示读到的字符串
* b" ]7 i c3 C7 H) w! q5 }7 d - }
+ |' v% w; ?: O8 n# [ - i++;
6 v# R" C$ f! A' V3 z* F0 u! o - delay_ms(10);
3 v6 q7 E/ d. c5 w. W! j& m0 ?; c - if(i==20)
# I P9 }2 g7 O% ~; Z! E. a - {
; q0 H' m) c, Z, |" T" @ - LED1=!LED1;//提示系统正在运行
, }; O3 e: n, n3 q; P$ E* f - i=0;
1 p3 f& n# e. V6 L, q7 |( ]# x - }
' y, Q! P& B& \/ |# N8 W - }
# p* ~2 q5 C/ }: w9 r9 z) V# G - ) o8 k1 R2 g o, I& i+ ], Q
- }
复制代码 K# U: j, S4 {* k
. d5 e o8 Y) v( G5 N3 A, b# v2 ` |
STOP 的时序,好像不对吧