01. IIC简介8 L5 \( m/ {1 ~) J6 P4 X2 Y
IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。
: J4 S, u5 }8 ^6 f
( m* B! j x' N6 D/ J& FI2C 总线在传送数据过程**有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。
- [2 S: ~5 ?1 p# L _. C+ ]9 |6 I' I
开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。
/ S: n6 g6 O: @; H+ q+ N6 _" u结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。) F& Z3 I3 F- t
应答信号:接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。4 k# o8 m* C, V9 w) s
( J, D- n1 r5 Q* P9 @# H, u- ?% y
02. 功能描述
" E/ w* Q2 i! G% K- ~% i) m D" ?开机的时候先检测24C02是否存在,然后在主循环里面检测两个按键,其中 1 个按键(KEY1)用来执行写入 24C02 的操作,另外一个按键(KEY0)用来执行读出操作,在 TFTLCD 模块上显示相关信息。同时用 DS0 提示程序正在运行。) m2 F$ S. E3 ~7 R6 B7 P
4 T, L" ]6 H2 O7 Q
03. 硬件模块% p2 f q6 r/ d8 W: s* m ^
硬件资源有:
- c% `! j) d2 r1) 指示灯 DS0 d3 y2 Q* c9 S& S
2) KEY_UP 和 KEY1 按键 v: W0 E+ W: w
3) 串口(USMART 使用)
^3 K( o3 N( U5 i4) TFTLCD 模块3 j7 c( o; P. i5 d( u+ P
5) 24C02
) p7 i3 {# y: h6 R
- T% o9 q- o/ Y7 a( Y' |( w7 X
( R7 I \" ~: k; S* @" o! x; H, k/ Y" o/ g0 i5 i
04. 软件设计8 s: \- b+ H; b- ?
myiic.h* R4 K0 s: e4 G/ ^" K# _- W
- #ifndef __MYIIC_H/ X( d4 x7 D4 c
- #define __MYIIC_H
+ J) x6 I8 R0 e8 m( j* H* O - #include "sys.h" ( G/ O; F) S9 q+ s; g5 }% B$ r1 x
- % Z r+ P$ j% |6 m0 D2 {
- //IO方向设置. R- O2 B; F3 u! d# d5 [
- #define SDA_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;} //PB9输入模式
2 n) v$ u+ Y1 p1 x3 N; g - #define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //
" e1 J" R, B1 E& ~ - ' K/ X5 F$ V% t3 l
- //IO操作函数 `, R( s7 N. t$ P& l
- #define IIC_SCL PBout(8) //SCL" K( G6 d# Y9 }0 C
- #define IIC_SDA PBout(9) //SDA * t4 z! N# R4 l, T9 ?
- #define READ_SDA PBin(9) //输入SDA 5 q1 n' c! N8 ?- G7 S
# [/ T( a" G% s7 z- //IIC所有操作函数
# X6 ]' O; m% b6 i! ]+ O/ r - void IIC_Init(void); //初始化IIC的IO口
8 T2 k. X$ {2 B; G3 v - void IIC_Start(void); //发送IIC开始信号' S2 F) U8 I! _- E. c/ J3 Q
- void IIC_Stop(void); //发送IIC停止信号
5 k% K; f0 R [$ P( i h/ g - void IIC_Send_Byte(u8 txd); //IIC发送一个字节8 g8 [" k' o! `5 ^3 T
- u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节5 \3 i, Y N9 k2 a. @& p" e5 n- V- x B
- u8 IIC_Wait_Ack(void); //IIC等待ACK信号$ [4 b" H$ M2 |
- void IIC_Ack(void); //IIC发送ACK信号2 @. S8 o% r2 {; C% O
- void IIC_NAck(void); //IIC不发送ACK信号' v; o0 E# d* ]+ v5 G @. g
, y* F+ ^) Q/ |6 y- void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);4 Q4 A" G7 J, Y& p" J' n4 W' ~# x9 b
- u8 IIC_Read_One_Byte(u8 daddr,u8 addr); 8 J* L. j7 V3 I; H: k/ Z* m
- #endif
复制代码 - ~6 W5 \" i# h8 C2 F
myiic.c
% x9 E. @* y0 Y" n4 K
6 i2 w# f9 }% {) y/ C! X- #include "myiic.h". y$ [) H/ W; y# @! t7 p" b5 i
- #include "delay.h"
! f- q. R0 w! Q9 j
! b. W h! t; V6 `- //初始化IIC
& w+ |* a& b8 ~ T - void IIC_Init(void)
: Q7 {/ |' D5 o, Q. }1 C - { 1 s6 u9 \1 p. r3 M+ A7 Z2 t
- GPIO_InitTypeDef GPIO_InitStructure;( o# X7 a/ z+ J; l& ~! {
, @" ^3 }! s! s; s/ I9 E- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
5 W" Q! h' J: E2 {0 s& G - - I/ H) V# ~6 W
- //GPIOB8,B9初始化设置7 f" U& q2 A M: G) ^, I
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
) W3 d4 A5 t1 K9 w# { - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式8 X0 N% I# [) i; W" B
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出2 o) l5 r, s5 P5 e7 A
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
. x$ ~0 @* x: U; C& p6 J& |7 z - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
2 O+ N! q) \. c9 G - GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化' {$ l2 I* f, m. ~& @: T9 H6 M
- IIC_SCL=1;
' [( J b. V9 Q - IIC_SDA=1;# P" X/ @% J( l: `% k
- }
; C% [. I. T3 ?% m - //产生IIC起始信号- E; V5 F1 `9 h4 f5 R- o! h
- void IIC_Start(void)
Q1 B1 G& ^% ]; t7 {0 t) d9 q - {# K) T. P5 Q* V; q/ h
- SDA_OUT(); //sda线输出
' I) e* y" O5 a; n$ z+ a - IIC_SDA=1;
: R% J6 W5 [4 n- C - IIC_SCL=1;6 S% q# C* M7 x1 f( o/ ]! Q( E
- delay_us(4);
" O: l, D4 O4 i, A$ Y - IIC_SDA=0;//START:when CLK is high,DATA change form high to low ' e8 A8 s8 j* |# n$ ~7 t1 Y- w
- delay_us(4);' N& H1 n! b( A) p5 K# p
- IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 ! |% [' }9 \" H/ _, e8 s
- } - `1 M) r: d' p( g* e; i" v. d( {
- //产生IIC停止信号, _/ C) c, @8 }' i. l
- void IIC_Stop(void)
+ E: [0 Q3 Z0 D+ r' N- D: c) I - {
0 z7 V# n( _1 t. |) L4 c - SDA_OUT();//sda线输出, p0 H% p9 R. h3 |
- IIC_SCL=0;; l) Z9 b* b' }$ q5 g+ W
- IIC_SDA=0;//STOP:when CLK is high DATA change form low to high1 ] ^" M( l1 p% @
- delay_us(4);' ]1 h" Z5 L! ^, t3 k. E
- IIC_SCL=1;
1 u6 a4 o' y, B: b - IIC_SDA=1;//发送I2C总线结束信号
/ s8 X! m3 E, [6 p. L. j6 S% | - delay_us(4); 9 u) |* N5 |0 f8 w Z {
- }% z/ L# p: F& S/ `7 x" p( U. G
- //等待应答信号到来7 B3 F% J" S% d
- //返回值:1,接收应答失败* K7 s& r0 Z9 P
- // 0,接收应答成功: l/ s& p* Y9 G
- u8 IIC_Wait_Ack(void)
$ X2 C6 W+ }' d C0 M - {! R! I' t7 @8 P }% q
- u8 ucErrTime=0;- z6 L$ \# ~1 u4 G% l S r
- SDA_IN(); //SDA设置为输入
& x5 A+ o1 p7 V' L( `8 r3 A - IIC_SDA=1;delay_us(1);
) N& F2 I: n* x' u: m - IIC_SCL=1;delay_us(1); 9 `6 }0 Q: J( d+ g: c9 q
- while(READ_SDA)
" O6 a; _1 K2 @! r1 m+ q - { e! u# C7 d5 t& W2 ~7 v$ I
- ucErrTime++;( _6 h+ e( q) Z( N! b; S
- if(ucErrTime>250)* ^% E9 @& t8 X
- {
( D; y$ Z! G5 l+ h; g - IIC_Stop();& q! I! s: d+ w! j" Y) o q
- return 1;
+ G: Q7 C2 F- F/ F+ ] - }; f, x8 d3 {, N6 t7 H, F
- } V' Y0 z8 ]# Q# ?. `$ U
- IIC_SCL=0;//时钟输出0 2 {0 |6 b' h7 P$ b# @
- return 0;
& ^3 T: s, E, h0 @- {$ Z - } 0 x# z- v) h1 a, r: l6 x$ S. t" }
- //产生ACK应答. X0 Y! v$ ]/ L+ F" q
- void IIC_Ack(void). _9 z3 [' d6 b3 V4 @& r$ M# A
- {' Z$ Y) ~( n7 m; N1 V) G# X
- IIC_SCL=0;# K; }2 h" p& M- k
- SDA_OUT();
8 k! q$ T3 \& {& G* D - IIC_SDA=0;
4 x% g# {- ]; f0 o- ~ - delay_us(2);
& O. s# g- j9 X - IIC_SCL=1;) D* u, V, O8 J% L5 N" K
- delay_us(2);% T: | t' G: X. Q% L; d
- IIC_SCL=0;
, x& m) ^, k# j1 N& x - }
/ S$ L" n0 X; C - //不产生ACK应答
0 q% n, ~# L* C* d& `/ ^# @ - void IIC_NAck(void)
( m* `8 @$ i5 \ X$ C& G - {, B$ r+ i1 o# A3 K- Q7 n3 k$ E
- IIC_SCL=0;# H$ u. J8 }" C8 S0 U! N t6 L/ X
- SDA_OUT();# s2 `) I. H' G
- IIC_SDA=1;/ m$ X/ j' `' N0 _' [8 r
- delay_us(2);$ C* U9 S5 q- ^3 Y
- IIC_SCL=1;6 i7 C8 h, P( p7 U
- delay_us(2);
7 _( g0 j, @4 v8 ^! U+ r - IIC_SCL=0;
- n) ~% E) ]/ ] ?8 R6 [9 z/ C/ U - }
* q/ c" ^ U. s& o* W/ I - //IIC发送一个字节2 M! @1 b0 X- f/ k3 a8 l% Z
- //返回从机有无应答
4 D) b% t! U C; z - //1,有应答; w7 J+ R) E0 P+ A' ?+ Z* f7 T( n
- //0,无应答
, B. W9 L2 O5 C - void IIC_Send_Byte(u8 txd)
( A3 H) Z/ D: g M - {
: ~4 D# j; ^/ j - u8 t; T+ I% P! Z, G5 Y; B
- SDA_OUT(); / C' R" p2 D$ b1 Z4 U
- IIC_SCL=0;//拉低时钟开始数据传输* f7 a$ Y. t) \2 U5 g
- for(t=0;t<8;t++)7 R: ~9 ?/ O% _& F& Q% p0 \$ I
- {
6 G5 l: O8 `$ ^- V2 w0 i/ c( W - IIC_SDA=(txd&0x80)>>7;8 h& M# q2 h" e( ~8 x
- txd<<=1; 4 S H' z8 l/ S2 H; H& K
- delay_us(2); //对TEA5767这三个延时都是必须的* W7 Y8 [; b: N1 e* D& `5 V. |
- IIC_SCL=1;
, Z7 j/ F R) U& w8 ^; L: [9 J# L9 S - delay_us(2); " A4 l% R! v6 g8 a
- IIC_SCL=0; 8 Y- S% a( I" M- A0 a( [* e& q" T f
- delay_us(2);, z% j1 l6 r7 K8 O+ d
- }
" P- C! o, u% J/ B; I9 V% U) y" P - } 0 e$ a) K. ^: F+ {
- //读1个字节,ack=1时,发送ACK,ack=0,发送nACK
. U4 H+ t' q' c* c7 ^+ {! T - u8 IIC_Read_Byte(unsigned char ack)4 a3 m( u: L9 {5 g
- {# @, n$ x# A# k; u
- unsigned char i,receive=0;
* C$ {( y% H0 i; r2 z2 o+ ] G" w - SDA_IN();//SDA设置为输入
7 ]; W& P6 e' Y2 M) S4 G8 K! X6 ~+ I - for(i=0;i<8;i++ )4 {3 f% b: I0 `, i/ [- s$ ^8 e
- {
# B+ G( C) ]' y: v% R/ {' f) T - IIC_SCL=0;
( G5 H* h4 o1 b% K2 Q8 e - delay_us(2);7 `# x, ]8 [9 w7 a
- IIC_SCL=1;& Q9 s: z/ a% m2 z( B
- receive<<=1;" s: [, E: G3 n6 w6 K1 T; A
- if(READ_SDA)receive++;
" }$ u6 |' S- B4 H8 z - delay_us(1); & p; k/ q# `' r3 z
- } 8 O4 T: b+ s! C- m& D
- if (!ack)* j+ D3 E% n( d$ z, w$ Y s |: ~6 T
- IIC_NAck();//发送nACK
1 |$ B( `7 F+ W& Q- I - else
@6 r4 }7 j+ K+ T. A2 q$ r) i - IIC_Ack(); //发送ACK
9 {2 u2 I ]7 i! m - return receive;7 s0 y9 q1 @4 _ Z2 y
- }
复制代码 1 r. D7 U+ g/ g- ~; T. t# w* J. \
main.c
; q# d. x& a7 I2 a( @- #include "sys.h"
8 g1 ~ P" i. L6 r! }/ I+ ~ - #include "delay.h") r( h; R* J) V# J! X
- #include "usart.h"
' G: P& |6 T8 f$ F; y2 d. J" o3 W - #include "led.h"
3 R4 } R" c- b* h, q9 A' ?1 ?( D9 |" { - #include "beep.h"
3 H, N/ U0 _+ l G - #include "key.h"
0 p, h; `/ ?1 {: [$ j - #include "usmart.h"
4 |- y! E# n9 j* Z: H5 M, Y - #include "lcd.h"
, }$ ^5 x6 b# f) R5 @7 o0 R - #include "rtc.h"
3 J8 P' k" b+ T7 u. {" i - #include "rng.h"% l3 L+ s# [3 e/ k. S/ Q; B* I
- #include "key.h"
% x i# J' j, w" R - #include "wkup.h"$ ?1 f2 o- e0 P7 |9 y- C; O; u
- #include "adc.h"
' z r. G1 p! R7 m) a# ~+ z - #include "dma.h"
[9 W5 f" Q1 P5 P6 \ - #include "24cxx.h"; x, x: c. m/ x) S
- 2 j; I2 \& N9 n2 {* h0 P' c
( \" S# M! W3 X- //要写入到24c02的字符串数组0 A0 k! U4 \' Z/ F, l, U
- const u8 TEXT_Buffer[]={"Explorer STM32F4 IIC TEST"};
{! ?+ w) K; E8 L* | - #define SIZE sizeof(TEXT_Buffer) / j+ e! i9 u. P ?9 N p
- $ P$ z, ?2 t' u% d6 D+ C
- [3 x1 e* x. n4 u6 P7 l' S- int main(void)' r9 [3 W8 w5 ^9 m1 o$ d
- {
0 Y, J* z- O% s E7 d - u8 key;& \7 ^( J- j, |9 c
- u16 i=0;8 V5 b! @; b; F7 `0 q, h6 J) h( I
- u8 datatemp[SIZE]; : F N: v: J$ f7 `
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
& l) F& C: g- P( Q% ?8 n - delay_init(168); //初始化延时函数$ E$ U$ m8 ^0 F0 I" j+ d3 [
- uart_init(115200); //初始化串口波特率为115200
@7 x7 s: e& {6 \; B -
) O" R% [4 |1 t5 H# a - LED_Init(); //初始化LED , `& W( p) R& R2 a1 c- u
- LCD_Init(); //LCD初始化 + d5 Y y5 j; r" t! s% U! |) P
- KEY_Init(); //按键初始化 " a7 r; R4 Y1 D$ l' _( K
- AT24CXX_Init(); //IIC初始化 ( F- H9 A! p) l4 d
- POINT_COLOR=RED;
W6 K( L! p+ c5 M% _; a - LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");
; `3 e6 X& w |3 Z - LCD_ShowString(30,70,200,16,16,"IIC TEST"); ! O: C" ?% Z j1 \- _( R
- LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");" M; R" s. Q% y0 w& R# f
- LCD_ShowString(30,110,200,16,16,"2014/5/6");
" s* q& m; V( J+ @, V( t - LCD_ShowString(30,130,200,16,16,"KEY1:Write KEY0:Read"); //显示提示信息
3 H+ ~; P* z4 ?1 h$ I - while(AT24CXX_Check())//检测不到24c02! ^, [8 M, _/ S& I
- {
- `( O6 V9 S9 z$ ^% L - LCD_ShowString(30,150,200,16,16,"24C02 Check Failed!");; A0 i/ P3 t0 P3 u P
- delay_ms(500);
) R5 Z& D: e2 ~3 L& [- A - LCD_ShowString(30,150,200,16,16,"Please Check! ");
~7 `+ }- U$ | q - delay_ms(500);8 X0 s. {3 N4 V. `
- LED1=!LED1;//DS0闪烁
R: V# K5 ~; k: o, y6 n - }
8 k0 q/ n. T8 ]: G - LCD_ShowString(30,150,200,16,16,"24C02 Ready!"); / L9 e% c N+ R/ f( H$ Z5 K0 }
- POINT_COLOR=BLUE;//设置字体为蓝色 , M9 `( ?# I/ V7 c; m6 {
7 {) I) {/ r6 \' _+ C9 m# z- while(1)
?% Q( Y5 ^9 t* z ~7 u - {
w; k5 U8 @# y5 ? - key=Key_Scan();
' w: q5 G- S. |1 G/ d7 a - if(key==KEY1_PRESS)//KEY1按下,写入24C02
" ~! Y9 w! n( L7 m* t - {
% Q2 d/ ~4 I* C! C4 {7 H+ h - LCD_Fill(0,170,239,319,WHITE);//清除半屏
1 ?7 }: j: S$ U$ M! p# W - LCD_ShowString(30,170,200,16,16,"Start Write 24C02....");$ z# D J4 E" {3 m% P9 Z
- AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);' G4 F0 s& c, w( G4 N
- LCD_ShowString(30,170,200,16,16,"24C02 Write Finished!");//提示传送完成
+ u8 F" Y- Z4 h; `' a7 s - }8 t! `( I7 P+ r3 X
- if(key==KEY0_PRESS)//KEY0按下,读取字符串并显示
$ q& E1 K7 Q6 l3 { - {. B$ Z ^/ @4 I0 o
- LCD_ShowString(30,170,200,16,16,"Start Read 24C02.... ");
+ E+ {0 v0 {6 B# k, b& A% |/ X - AT24CXX_Read(0,datatemp,SIZE);
9 y7 ]/ E/ I0 K1 I$ Y - LCD_ShowString(30,170,200,16,16,"The Data Readed Is: ");//提示传送完成( Y7 Y: j! K7 a% G5 F( \
- LCD_ShowString(30,190,200,16,16,datatemp);//显示读到的字符串
' ?8 K7 K4 P7 Z# x2 R" r, K# ^ - }: {0 [2 F9 R/ w" p
- i++;# Q7 `; b* n7 h8 O
- delay_ms(10); t. ?1 Z/ q! i- x3 P; p
- if(i==20)
0 O. c4 d. g/ y; s* h' W9 ] - {4 x: x' W- s( F& e
- LED1=!LED1;//提示系统正在运行 1 y0 x5 _2 P% h( G3 M5 V
- i=0;$ |1 v! \! N2 Y4 k
- }
* V$ M: ~" |9 r4 T, ?1 x. ] - } , x( g0 {/ c. f3 m" h1 g
-
0 ]$ d5 \: a3 J( r7 {* `, b - }
复制代码 # ? I' M$ p' w Z4 H, C w' d5 L
( k3 R3 q+ |( {6 } |
STOP 的时序,好像不对吧