1. 延时函数编写

这是systick寄存器

delay.c函数部分如何

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void Delay_Init(void)
{
systick_clksource_set(SYSTICK_CLKSOURCE_HCLK);
//首先选择时钟源,选择外部时钟,这里为108mhz,不分频
}

void Delay_us(uint16_t us)
{
/*配置systick寄存器*/
SysTick->LOAD = 108*us; //设置自动重载值,因为这里是108mhz,所以要乘以108
SysTick->VAL = 0; //设置此位为自动清理SysTick_CTRL_COUNTFLAG_Msk为0
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开启systick
while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭systick
}

void Delay_ms(uint16_t ms)
{
while (ms--)
{
Delay_us(1000);
}
}

2. 软件IIC编写

iic.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "gd32f10x.h"
#include "delay.h"
#include "iic.h"

void IIC_Init(void)
{
/*开启时钟源*/
rcu_periph_clock_enable(RCU_GPIOB);

/*设置为开漏输出模式*/
gpio_init(GPIOB,GPIO_MODE_OUT_OD,GPIO_OSPEED_50MHZ,GPIO_PIN_6);
gpio_init(GPIOB,GPIO_MODE_OUT_OD,GPIO_OSPEED_50MHZ,GPIO_PIN_7);

IIC_SCL_H;
IIC_SDA_H;
}

/**
* @brief 起始信号,在scl高电平期间拉低sda
*
*/
void IIC_Start(void)
{
IIC_SDA_H;
IIC_SCL_H;
Delay_us(5);
IIC_SDA_L;
Delay_us(5);
IIC_SCL_L;
}

void IIC_Stop(void)
{
IIC_SCL_H;
IIC_SDA_L;
Delay_us(5);
IIC_SDA_H;
}

void IIC_Send_Byte(uint8_t Byte)
{
int8_t i;
for( i = 7; i >= 0 ; i--)
{
IIC_SCL_L;
if(Byte & BIT(i))/*这里是高位先发送*/
{
IIC_SDA_H;
}else
{
IIC_SDA_L;
}
Delay_us(5);
IIC_SCL_H;
Delay_us(5);
}
IIC_SCL_L;
IIC_SDA_H;/*释放SDA*/
}

uint8_t IIC_Wait_Ack(int16_t timeout)
{
do
{
timeout--;
Delay_us(2);
}while(IIC_READ_SDA && (timeout >=0));
if(timeout < 0 ) return 1;
IIC_SCL_H;
Delay_us(5);/*判断是否有稳定的低电平*/
if(IIC_READ_SDA) return 2;
else
{
IIC_SCL_L;
return 0;
}
}

uint8_t IIC_Read_Byte(uint8_t ack)
{
int8_t i;
uint8_t byte;
IIC_SDA_H;
for (i = 7; i >= 0; i--)
{

IIC_SCL_L;
Delay_us(5);
IIC_SCL_H;
if(IIC_READ_SDA)
{
byte |= BIT(i);
}
Delay_us(5);
}
IIC_SCL_L;
Delay_us(5);
if(ack == 0)
{
IIC_SDA_L;
IIC_SCL_H;
Delay_us(5);
/*为下一次接收做准备*/
IIC_SCL_L;
IIC_SDA_H;
Delay_ms(5);
}
else
{
IIC_SDA_H;
IIC_SCL_H;
Delay_us(5);
IIC_SCL_L;
Delay_us(5);
}
return byte;
}

iic.h

1
2
3
4
5
6
7
#define IIC_SCL_H  gpio_bit_set(GPIOB,GPIO_PIN_6)
#define IIC_SCL_L gpio_bit_reset(GPIOB,GPIO_PIN_6)

#define IIC_SDA_H gpio_bit_set(GPIOB,GPIO_PIN_7)
#define IIC_SDA_L gpio_bit_reset(GPIOB,GPIO_PIN_7)

#define IIC_READ_SDA gpio_input_bit_get(GPIOB,GPIO_PIN_7)

3. m24c02数据手册解读

1.从机地址

  1. 从机地址写使能1010,原理图这里E2,E1,E0全部接地,所以==写使能0xA0,读使能0xA1==

2. 连续写字节和单独写字节

​ 单独写一个字节:

​ 依次发送从机写使能,寄存器地址,数据3个操作

​ 由24C02的数据缓存器只有16个byte(每个型号的存储IC的页大小是不一样的也就是缓存器大小是不不一样的)。所以如果写入的数据超过缓存器的大小就会覆盖之前写入的数据.就是说m24c02有一个16个byte的缓冲区,我们写字节是往缓冲区里面写,不再产生信号,m24c02才开始搬运数据,

​ 这里意思是,能够最多连续写16给字节,但是只能写在一页中,一页就是0-15,16-31,… 255,如果写多了就会发生回滚操作,我们每发送一个字节,都要收到应答,应答后再发送即可.

​ m24c02.c代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include "gd32f10x.h"
#include "m24c02.h"
#include "iic.h"
#include "string.h"
#include "main.h"

uint8_t M24c02_WriteByte(uint8_t addr, uint8_t byte)
{
IIC_Send_Byte(M24C02_WADDR);
if(IIC_Wait_Ack(100) != 0) return 1;
IIC_Send_Byte(addr);
if(IIC_Wait_Ack(100) != 0) return 2;
IIC_Send_Byte(byte);
if(IIC_Wait_Ack(100) != 0) return 3;
IIC_Stop();
return 0;
}


uint8_t M24c02_WritePage(uint8_t addr, uint8_t *wdata)
{
uint8_t i = 0;
IIC_Send_Byte(M24C02_WADDR);
if(IIC_Wait_Ack(100) != 0) return 1;
IIC_Send_Byte(addr);
if(IIC_Wait_Ack(100) != 0) return 2;
for( i = 0; i < 16; i++)
{
IIC_Send_Byte(wdata[i]);
if(IIC_Wait_Ack(100) != 0) return 3+i;
}
IIC_Stop();
return 0;
}


uint8_t M24c02_ReadData(uint8_t addr, uint8_t *rdata,uint8_t len)
{
uint8_t i = 0;
IIC_Send_Byte(M24C02_WADDR);
if(IIC_Wait_Ack(100) != 0) return 1;
IIC_Send_Byte(addr);
if(IIC_Wait_Ack(100) != 0) return 2;
/*发送读指令*/
IIC_Start();
IIC_Send_Byte(M24C02_RADDR);
if(IIC_Wait_Ack(100) != 0) return 3;
for( i = 0; i < len - 1 ; i++)
{
rdata[i] = IIC_Read_Byte(0);
}
rdata[len-1] = IIC_Read_Byte(1);
IIC_Stop();
return 0;
}