01. IIC简介1 n* Q, w0 b( l/ u
IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。& n8 ^8 Q! s; h( a* r0 U
& _# h0 {9 s }
I2C 总线在传送数据过程**有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。, q: r6 L4 B7 a
! I$ v* \$ U* J9 Z( E. B
开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。! R9 D7 f; w4 o- A( f5 ~/ j
结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。
; U# n. b5 C/ X3 X7 j! U+ {8 f& W应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。; t0 a5 o# o2 y4 j" t) b! [( a1 |
) v) d" h k0 b! k6 f% P
02. 功能描述% B# u8 l% K/ d' U1 d3 i+ W5 D
开机的时候先检测24C02是否存在,然后在主循环里面检测两个按键,其中 1 个按键(KEY1)用来执行写入 24C02 的操作,另外一个按键(KEY0)用来执行读出操作,在 TFTLCD 模块上显示相关信息。同时用 DS0 提示程序正在运行。
2 Q. [, h2 a8 s/ N7 Y2 C# u% K- a& v( \5 A8 ?0 k$ P/ {% n$ n0 B3 @
03. 硬件模块
9 ?6 Z) U. L8 O$ N( o& U/ j) C% `( D硬件资源有:" ~0 N$ Z5 S/ f/ V
1) 指示灯 DS05 L3 u3 n4 |% @
2) KEY_UP 和 KEY1 按键6 z1 A$ @, O; v# ~9 Z4 h6 a2 U9 x
3) 串口(USMART 使用)2 ~+ c# P7 e' L
4) TFTLCD 模块- d$ j: d; U' p% b0 B" P+ Q% d
5) 24C024 c% ^7 W5 K* m6 U
' \$ U. n6 l E0 u- ~; H( Y
1 q( N! N7 F. ]; {$ O* c/ `
" q+ h w" i4 u. q- c04. 软件设计* i4 ~2 t1 N8 b6 `4 G: u
myiic.h
! g. @1 n+ U, x* ?& i c* @" h' U' ]" P/ U9 ^. Z
- #ifndef __MYIIC_H
. i C% ]6 q5 M7 P. N1 U; n - #define __MYIIC_H
9 b Q8 i" d7 R2 ^1 {5 Z3 Z - #include "sys.h"
* G z& e3 L" U# `% u" s - ; D( S& R$ k. l- O
- //IO方向设置
, N- e0 I \/ g" z" O# v0 d - #define SDA_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;} //PB9输入模式; E$ T# N* z. R' R1 P# @# c
- #define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //' i1 Q5 D* A: U* R3 G
2 q, {; v: z% Y) |2 f- //IO操作函数 : P! j% B. B& h/ L/ i; r( [
- #define IIC_SCL PBout(8) //SCL1 \& x; [2 e. }# {1 Y2 Q
- #define IIC_SDA PBout(9) //SDA ; i# W1 y7 F4 i: N
- #define READ_SDA PBin(9) //输入SDA
' j% r4 e; ?' k8 e% A
- o4 P* F& f# F: I. d- s3 P- //IIC所有操作函数
/ b V* P; U! } w% t$ D - void IIC_Init(void); //初始化IIC的IO口 1 N# V% d# h8 \7 }* X& c# e7 h. H0 W
- void IIC_Start(void); //发送IIC开始信号! W+ _% w+ [5 E8 b/ q
- void IIC_Stop(void); //发送IIC停止信号( w3 ^; `& b0 |7 `/ o4 e, U5 N$ x' y
- void IIC_Send_Byte(u8 txd); //IIC发送一个字节
7 q1 y8 x2 t6 d$ ^% z9 @ - u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节& W9 S, u0 e% x" m0 _
- u8 IIC_Wait_Ack(void); //IIC等待ACK信号9 F4 I# g. g: Z# j
- void IIC_Ack(void); //IIC发送ACK信号& [2 T7 [* o" g/ Y, g+ C
- void IIC_NAck(void); //IIC不发送ACK信号) J; f8 A# P- F2 F5 \( @
- 0 E: k6 y7 h9 I' k6 `6 c0 n' `
- void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
& a8 s/ k) |( s" l2 b, B! q - u8 IIC_Read_One_Byte(u8 daddr,u8 addr); ; q6 ?* H" [# g% X' Z+ }0 x
- #endif
复制代码
/ ?" y+ D; ^: x# W2 b& dmyiic.c
) l. v3 W) }! ^
, x- H$ e- H4 ~ {8 e- #include "myiic.h"7 Y- s# I# [/ P$ K4 f6 U( Z
- #include "delay.h"
* E7 h1 r3 H( }! t - - X; U$ M, V$ ? u1 @
- //初始化IIC' p3 h+ y g% q8 d0 b: Y
- void IIC_Init(void)
H V) U- t. Q! Y; s - {
1 G4 [/ t* j) ~6 V9 ^ - GPIO_InitTypeDef GPIO_InitStructure;
! s8 I+ U e" l" y$ i - " x# p1 w8 g/ f3 W X& u
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
# q: S o) l5 |% t - 7 @, d9 Q( b& x& J
- //GPIOB8,B9初始化设置
" M4 ]- V/ |, z E( d# w$ @0 W# O - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;3 d2 _3 { L8 [- l& G; u- s; s
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
9 `* N9 m" n( p - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
4 c4 r+ X0 [+ E& B5 ~ - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz5 S4 c# s" e* Z9 O! a
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
1 r' A; N: b. v/ [0 X& W% |2 { - GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
3 P; J" V& p% F2 t- U7 E - IIC_SCL=1;
. v6 G( n5 t; V$ I2 i7 C7 x& D Q" ^ - IIC_SDA=1;! a1 i: w6 Z7 n( M3 o+ E
- }6 }6 m' _+ d0 f5 g' H1 u6 J
- //产生IIC起始信号) F! v3 N4 p! P) x
- void IIC_Start(void)
2 h" q; ?( Y+ S( o* A/ v0 Z - {
) x) B5 y4 q8 N' `0 h/ F - SDA_OUT(); //sda线输出
. ^( M/ K2 w( m) K; }* W/ W! d0 ~2 } - IIC_SDA=1; 0 _: p9 u! H( W7 L0 D
- IIC_SCL=1;
4 ] v0 t' y1 g - delay_us(4);! y, W" w# P( h% y5 i, J7 A! t! @
- IIC_SDA=0;//START:when CLK is high,DATA change form high to low % `- u. O. u$ j6 I z! c, n
- delay_us(4);/ j/ R! k6 V% i& O8 {9 B' H$ x
- IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
$ [5 ^& s4 o4 M2 W5 n+ p$ Z - }
; J: @, N7 J' \* k' ]' ^! ^- b - //产生IIC停止信号% ]1 _; {) S% w8 O
- void IIC_Stop(void)6 P5 L& I+ _* |
- {
+ }# |, Z9 Q( l; @ - SDA_OUT();//sda线输出
$ x. U& O% Q- f - IIC_SCL=0;
8 p9 H$ C+ Q% I% l! J5 _ - IIC_SDA=0;//STOP:when CLK is high DATA change form low to high9 L1 |4 d" p& z1 X, B8 p, R! n: W
- delay_us(4);3 W/ T7 a) b1 K. R( ]( M+ h
- IIC_SCL=1;
8 ~. b+ n( Y" g9 n$ a6 _ - IIC_SDA=1;//发送I2C总线结束信号
! b1 J( K( i6 f) A" M! Q5 v$ K - delay_us(4); # A3 r5 [/ j2 o" s" u/ V# G, V
- }
1 }! B" r* a5 B6 k - //等待应答信号到来* J3 k3 b! `2 g4 J
- //返回值:1,接收应答失败
$ N2 e, u/ M, a# P' m - // 0,接收应答成功1 o- `5 g. R k' ] k2 B
- u8 IIC_Wait_Ack(void)
* a* ^! t* m9 }0 K# f - { v" E5 e- z" Y! d' M
- u8 ucErrTime=0;
7 D3 O3 i# v( o' @3 \ - SDA_IN(); //SDA设置为输入 " n4 r: q) X$ G7 X0 g7 @' ]. V
- IIC_SDA=1;delay_us(1); 1 \9 S! r' A$ \+ Q" W& ]
- IIC_SCL=1;delay_us(1);
4 d. D+ Q: c& d6 q+ X# X; { - while(READ_SDA)
8 y5 E/ s% J8 L0 Z- s) U; K - {) M! Q0 S- N' ?& o1 K5 p; s' }
- ucErrTime++;2 M* g( J1 j! |* s! V6 l
- if(ucErrTime>250)
# C# o5 l5 l8 D - {
9 p `1 W9 _4 C$ K8 v - IIC_Stop();# C7 O7 E* f# l. ~
- return 1;
- k/ z/ w6 `; M4 r2 T - }
& u1 W5 `0 I, [: ^ - }# d# u$ ]: C2 N" q7 F7 j
- IIC_SCL=0;//时钟输出0
3 ]! m' e: }5 @3 m. x2 T - return 0;
N4 o2 |6 X% u O8 f: m - } # R( b; p7 j" v; E
- //产生ACK应答
! i/ z5 z3 C* [' K! n w+ n - void IIC_Ack(void)
; v6 |5 j7 d& C6 p8 x7 E! `# U - {, h4 E8 m H; b- m; O, r/ Y I
- IIC_SCL=0;- i0 r2 P H* H3 R4 G# W
- SDA_OUT();7 ^7 c; C( u- K* _
- IIC_SDA=0;5 h8 w" @( J( m% q# N
- delay_us(2);
2 D5 h: A( A5 l - IIC_SCL=1;
% e' M2 g) X) |( ]1 t - delay_us(2);* A/ W A5 C* U. p
- IIC_SCL=0;, A$ @( z- P# X' Z2 ?4 P
- }
! f' t# s) c$ m; k- P& W- U2 | - //不产生ACK应答
# e7 i1 N+ r% s! o9 H1 p - void IIC_NAck(void)* L$ `7 O7 ^* ]2 V3 g
- {3 ~7 { S0 Q) w0 ]3 w& h
- IIC_SCL=0;9 u; O- y7 y9 D# N% e
- SDA_OUT();7 L" l& G7 O; \; g2 s* v
- IIC_SDA=1;
4 h7 H, m- o5 O' J. g7 h, I7 }1 I - delay_us(2);
* u' I9 n! Y% k$ B3 T; ] - IIC_SCL=1;( @& |+ ]! g% I1 a) v
- delay_us(2);2 T r4 U' l8 \2 ]: G' Q9 F1 {+ j' z+ y B" s
- IIC_SCL=0;! J3 H8 [1 ?: x
- }
! U1 z5 W$ a) O3 C( ], x i - //IIC发送一个字节 h" R% r) { ^8 T" t
- //返回从机有无应答
4 j6 t# x2 v$ w* J1 k( e, V - //1,有应答
. g% g) q" t8 ?1 U" ^% Z6 ~1 } - //0,无应答
" H& o( K/ r U5 V; w- u: M1 L - void IIC_Send_Byte(u8 txd)" M. V3 m$ \3 q+ Y0 S, K
- { / x- z0 E% v3 q! j' s
- u8 t;
6 G' l3 {8 [* P$ z3 P6 W% D - SDA_OUT();
4 Q' V% O1 a7 S' g8 ^7 f; i9 l, `* E - IIC_SCL=0;//拉低时钟开始数据传输
. x S$ o) G, U9 ^, ~% z/ D- `. l - for(t=0;t<8;t++)
: B; m# a, U! L) b - {
8 M8 R% l- ` E ` - IIC_SDA=(txd&0x80)>>7;/ ?; g" F, c p$ B* d
- txd<<=1; 4 z* b0 s8 p6 Z( I0 C
- delay_us(2); //对TEA5767这三个延时都是必须的6 ^2 `! f( v2 b
- IIC_SCL=1;
$ I! T" @7 D" Y0 o: E - delay_us(2);
: l; t0 }% Q- S6 ?7 ~! v - IIC_SCL=0;
6 N( q4 B# X& s/ N - delay_us(2);
* x% n6 ^) {$ ~8 g - }
% k% H7 {4 x" W4 j& F, m - } 1 F$ v$ W8 u3 O) j0 b8 t- }
- //读1个字节,ack=1时,发送ACK,ack=0,发送nACK 8 ~+ M* b; Q# n/ b! x
- u8 IIC_Read_Byte(unsigned char ack)
1 V* h; X; Y1 y. G - {
. R) d& r( C. X+ D5 E1 W( t3 d - unsigned char i,receive=0;! s- q) z* _! P1 A
- SDA_IN();//SDA设置为输入 a6 @, o9 @. g8 ? @' [+ ^$ ^
- for(i=0;i<8;i++ )
) R# Y; X+ Y% \9 L5 u1 Q7 W - {
3 A! _' K8 r# ^( P9 y2 H7 l - IIC_SCL=0;
. J% x" u8 X8 K9 _# P; I$ j - delay_us(2);( o( s4 B" S" G& |( R1 Y
- IIC_SCL=1;4 Y4 [0 D9 B2 j6 i" U5 m5 V
- receive<<=1;" c! X8 d6 B7 @
- if(READ_SDA)receive++;
( g# c6 Y( s2 @; E. S3 H - delay_us(1); 9 z2 j; T+ \) C: `! O; ^
- } 2 r, c1 [3 z6 ~+ ^' O, X3 n/ i
- if (!ack)
9 y' I8 K( `( {. l - IIC_NAck();//发送nACK) v/ @" } ]$ c7 w
- else' `3 o+ T- w2 h8 e0 e
- IIC_Ack(); //发送ACK
$ j4 L3 p) c- A) h: }! s - return receive;
! u) y% g$ @- F7 k$ a. W2 l v - }
复制代码 : p" D! W% T4 F: f. F" |
main.c/ P3 I& t8 m5 g. v+ O7 p7 d/ P
3 s d& v# E7 @- Q& i/ Y
- #include "sys.h"
8 E& K" Z& u! Z& T- C8 r - #include "delay.h"/ [% N3 j6 D. ?* H' G4 U
- #include "usart.h"3 z4 w& n1 h; b8 Y* v$ }! ]
- #include "led.h"* q9 z% O2 H! x: o9 {
- #include "beep.h"3 _4 a9 H: h$ A6 T! w g2 ?
- #include "key.h"
. B; c# A* ?$ n3 S - #include "usmart.h"
* `: U" M4 T) p9 E - #include "lcd.h"
& U/ x+ ?2 g' [' R6 o m% k - #include "rtc.h"& ]0 Z D' i- y+ c j# a- S+ s9 x
- #include "rng.h" f8 C5 f& d6 E" `! {9 _
- #include "key.h"
. w' w1 L+ F9 U; e& x6 Q' b5 _ - #include "wkup.h", ?6 v5 X2 G4 w4 W4 D" d1 V8 m. S3 w
- #include "adc.h"
& h1 y, C, w9 ^" ~ - #include "dma.h"
+ a+ T9 e. O e% V( }/ k M$ b - #include "24cxx.h"; a# R3 U3 Z' y6 y# O6 { z
9 }% j$ O9 D" L$ o1 W$ S( \; D- D- : O4 y+ Y4 m% K$ h" ]* }1 p! J( W
- //要写入到24c02的字符串数组' U! }$ `2 t6 M, i$ m( T
- const u8 TEXT_Buffer[]={"Explorer STM32F4 IIC TEST"};
; f( e: K5 m, \' J( R8 X0 e4 t - #define SIZE sizeof(TEXT_Buffer) 7 ]7 z2 t" X" d9 T4 F' g
& b2 b# C' Q- P+ v- - T/ s! h2 F! }# l+ X0 p
- int main(void)% W6 o' P2 q \
- {
. s9 t2 w- v4 t/ S; F - u8 key;
( g* [8 D5 K, c - u16 i=0;1 m8 U6 U$ _* K1 I; Z! ^! _3 }# f+ ]" w
- u8 datatemp[SIZE]; 8 Y7 Y. I. I1 @1 |* J: Y# e
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
: Q7 x+ y4 k K4 r/ b - delay_init(168); //初始化延时函数
! Y0 T2 H8 p+ i4 _1 T& P - uart_init(115200); //初始化串口波特率为115200
) s" I4 {, C4 i) m7 V5 l: T9 Y: P - 2 [/ v5 i& ]! M3 L5 ~/ T: _
- LED_Init(); //初始化LED
# F% d7 |" `1 F7 e( V1 T - LCD_Init(); //LCD初始化
- W" S9 u# S6 k) {: _ H - KEY_Init(); //按键初始化 0 u5 M2 D7 t7 c
- AT24CXX_Init(); //IIC初始化 5 [# \7 c' j* Y* F8 e
- POINT_COLOR=RED; 3 V7 R3 j8 [6 A- P6 v7 s3 v
- LCD_ShowString(30,50,200,16,16,"Explorer STM32F4"); , O! l8 a! }$ v/ D& {' D
- LCD_ShowString(30,70,200,16,16,"IIC TEST"); 9 A6 N) t* \+ h
- LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");) ?. h8 A+ R& b' b V
- LCD_ShowString(30,110,200,16,16,"2014/5/6"); 2 S4 o+ M9 a1 P* O+ m% c
- LCD_ShowString(30,130,200,16,16,"KEY1:Write KEY0:Read"); //显示提示信息
& B$ p1 |# p+ n7 ? - while(AT24CXX_Check())//检测不到24c02& V+ x* Y; c8 v% l! x0 [
- {" Z6 m' f& |) b: B; l
- LCD_ShowString(30,150,200,16,16,"24C02 Check Failed!"); w) f. Z9 L* Z k6 b7 N# e8 ~5 X
- delay_ms(500);
. z5 q) h# u4 l5 A$ X1 i6 ~8 u9 I4 o3 { - LCD_ShowString(30,150,200,16,16,"Please Check! ");
" ]: S/ ?9 e+ [0 j% g6 Z - delay_ms(500);
1 _5 K" [: |$ [5 o* ?# F8 F5 } - LED1=!LED1;//DS0闪烁
+ T& G- w$ i0 {: {0 g - }
+ B% r! i c. P - LCD_ShowString(30,150,200,16,16,"24C02 Ready!"); 0 y {! [) g& U$ I7 Z d
- POINT_COLOR=BLUE;//设置字体为蓝色 8 e8 H( W. }" w6 y7 V
- 8 h3 l3 |) m8 D5 c& m
- while(1)
, s9 ~ M. ]) {1 v5 d - {. Q4 k! i b6 x! w
- key=Key_Scan();
- ^4 g$ P$ M5 |. X4 u& A - if(key==KEY1_PRESS)//KEY1按下,写入24C02
[1 d! G9 |* Q# W6 } z - {
4 W/ @: g3 ?! P- Z2 ? - LCD_Fill(0,170,239,319,WHITE);//清除半屏
% A4 B( ? E8 ]# O/ l - LCD_ShowString(30,170,200,16,16,"Start Write 24C02....");1 j; ^( m4 U3 V8 I
- AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);
. Q2 I- N3 e/ k6 e( D$ }, c. D/ n - LCD_ShowString(30,170,200,16,16,"24C02 Write Finished!");//提示传送完成
7 L& M( U% K$ M$ r) i) F - }# ~1 o4 n& N9 q$ h1 C: O
- if(key==KEY0_PRESS)//KEY0按下,读取字符串并显示2 a) m; k& r1 k, i1 o& X7 `, H
- {
% w3 V& ?! d, | H* q& ~5 Z6 | - LCD_ShowString(30,170,200,16,16,"Start Read 24C02.... ");
1 ^7 y- A9 P- N0 a5 B - AT24CXX_Read(0,datatemp,SIZE);
* C& ^' ~' T7 I+ j - LCD_ShowString(30,170,200,16,16,"The Data Readed Is: ");//提示传送完成, j- L/ \7 i! v E* @
- LCD_ShowString(30,190,200,16,16,datatemp);//显示读到的字符串/ {7 ?& |. i) z j$ C" G. W
- }
( y, U8 u4 B' d$ n1 C( z4 o - i++;. ]0 {, I9 H& y8 @7 [! y
- delay_ms(10);
0 c1 D6 s5 }9 t+ G0 R - if(i==20)
1 ^9 d- G+ Z$ @, W! D4 R - {
! F5 g9 q6 [7 T5 g# N1 T4 f* S - LED1=!LED1;//提示系统正在运行
6 B/ M5 _/ Z( ~9 z2 X0 f% V: E - i=0;4 [+ a8 w+ G$ y5 U/ u
- } 1 {) |, Q4 ^7 V. ~
- }
0 m# ?! `" O# N2 N' F* c( a -
! |6 R. d) i: u, l" T0 r - }
复制代码
) B3 _, P' J6 u+ ^+ p6 }* O6 H$ U7 J+ `
( g! F/ m* B& c4 T |