• STM32MP157 I2C和SPI总线实验


    I2C.h

    
    #ifndef I2C_DRIVER_H
    #define I2C_DRIVER_H
    
    #include "gpio.h"
    
    #define NACK 				1
    #define ACK					0
    
    #define SCL_PIN 			14
    #define SCL_PORT			GPIOF
    #define SCL_PIN_CLK_EN()	do{RCC->MP_AHB4ENSETR |= (0x1 << 5);}while(0)
    
    #define SDA_PIN 			15
    #define SDA_PORT			GPIOF
    #define SDA_PIN_CLK_EN()	do{RCC->MP_AHB4ENSETR |= (0x1 << 5);}while(0)
    
    #define SCL_H()				do{GPIOF->BSRR |= (0x1 << 14);}while(0)
    #define SCL_L()				do{GPIOF->BRR |= (0x1 << 14);}while(0)
    #define SCL_INPUT()			(GPIOF->IDR & (0x1 << 14))
    
    #define SDA_H()				do{GPIOF->BSRR |= (0x1 << 15);}while(0)
    #define SDA_L()				do{GPIOF->BRR |= (0x1 << 15);}while(0)
    #define SDA_INPUT()			(GPIOF->IDR & (0x1 << 15))
    
    #define I2C_Delay()			us_timer_delay(10)
    
    void us_timer_delay(unsigned short t);
    void I2C_Init(void);
    void I2C_SDA_OUT(void);
    void I2C_SDA_IN(void);
    void I2C_Start(void);
    void I2C_Stop(void);
    void I2C_ACK(void);
    void I2C_NACK(void);
    unsigned char I2C_GetACK(void);
    void I2C_SendByte(unsigned char data);
    unsigned char I2C_ReadByte(unsigned char ack);
    
    
    
    
    #endif
    
    
    • 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

    I2C.C

    #include "i2c_driver.h"
    
    void us_timer_delay(unsigned short t)
    {
    	unsigned short counter = 0;
    
    	while(t--)
    	{
    		counter=10;
    
    		while(counter--);
    	}
    }
    
    /* 初始化两个引脚 */
    void I2C_Init(void)
    {
    	/* 使能RCC时钟 */
    	SCL_PIN_CLK_EN();
    
        // 设置PF14,PF15引脚为通用的输出功能
        GPIOF->MODER &= (~(0xF << 28));
        GPIOF->MODER |= (0x5 << 28);
        // 设置PF14, PF15引脚为推挽输出
        GPIOF->OTYPER &= (~(0x3 << 14));
        // 设置PF14, PF15引脚为高速输出
        GPIOF->OSPEEDR |= (0xF << 28);
        // 设置PF14, PF15引脚的禁止上拉和下拉
        GPIOF->PUPDR &= (~(0xF << 28));
    
    
    	/* 拉高引脚电平 */
    	SCL_H();
    	SDA_H();
    	
    }
    
    /* 配置SDA引脚为输出 */
    void I2C_SDA_OUT(void)
    {
    	GPIOF->MODER &= (~(0x3 << 30));
    	GPIOF->MODER |= (0x1 << 30);
    }
    
    /* 配置SDA引脚为输入 */
    void I2C_SDA_IN(void)
    {
    	GPIOF->MODER &= (~(0x3 << 30));
    }
    
    /* 开始信号 */
    void I2C_Start(void)
    {
    	I2C_SDA_OUT();
    
    	SCL_H();
    	I2C_Delay();
    
    	SDA_H();
    	I2C_Delay();
    
    	SDA_L();
    	I2C_Delay();
    
    	SCL_L();
    	I2C_Delay();
    	
    }
    
    /* I2C停止信号 */
    void I2C_Stop(void)
    {
    	I2C_SDA_OUT();
    
    	SCL_L();
    	I2C_Delay();
    
    	SDA_L();
    	I2C_Delay();
    
    	SCL_H();
    	I2C_Delay();
    
    	SDA_H();
    	I2C_Delay();
    }
    
    /* I2C发出应答信号 */
    void I2C_ACK(void)
    {
    	I2C_SDA_OUT();
    
    	SCL_L();
    	I2C_Delay();
    
    	SDA_L();
    	I2C_Delay();
    
    	SCL_H();
    	I2C_Delay();
    	I2C_Delay();
    
    	SCL_L();
    	I2C_Delay();
    }
    
    /* I2C发出非应答信号 */
    void I2C_NACK(void)
    {
    	I2C_SDA_OUT();
    
    	SCL_L();
    	I2C_Delay();
    
    	SDA_H();
    	I2C_Delay();
    
    	SCL_H();
    	I2C_Delay();
    	I2C_Delay();
    
    	SCL_L();
    	I2C_Delay();
    }
    
    unsigned char I2C_GetACK(void)
    {
    	unsigned char time = 0;
    
    
    	SDA_H();
    	SCL_L();
    	I2C_Delay();
    
    	I2C_SDA_IN();
    	I2C_Delay();
    	I2C_Delay();
    
    	SCL_H();
    	I2C_Delay();
    
    
    	while (SDA_INPUT())
    	{
    		time++;
    		if(time>250)
    		{
    			SCL_L();
    			return 1;
    		}
    	}
    
    	SCL_L();
    
    	return 0;
    }
    
    void I2C_SendByte(unsigned char data)
    {
    	unsigned int cnt = 0;
    
    	I2C_SDA_OUT();
    	
    
    	for(cnt=0; cnt<8; cnt++)
    	{
    		SCL_L();
    		I2C_Delay();
    
    		if(data & 0x80)
    		{
    			SDA_H();
    		}
    		else
    		{
    			SDA_L();
    		}
    		I2C_Delay();
    		SCL_H();
    		
    		I2C_Delay();
    		I2C_Delay();
    		data = data<<1;
    
    
    		I2C_Delay();
    	}
    
    	SCL_L();
    	I2C_Delay();
    	I2C_GetACK();
    }
    
    unsigned char I2C_ReadByte(unsigned char ack)
    {
    	unsigned int cnt;
    	unsigned char data = 0xff;
    
    	
    
    	for(cnt=0; cnt<8; cnt++)
    	{
    		SCL_L();
    		I2C_Delay();
    		I2C_Delay();
    		SCL_H();
    		I2C_Delay();
    
    		data <<= 1;
    		if(SDA_INPUT())
    		{
    			data |= 0x01;
    		}
    
    		I2C_Delay();
    	}
    
    	if(ack == 0)
    	{
    		I2C_ACK();
    	}
    	else
    	{
    		I2C_NACK();
    	}
    
    	return data;
    }
    
    
    • 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
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229

    SPI.h

    #ifndef __SPI_H__
    #define __SPI_H__
    
    #include "stm32mp1xx_gpio.h"
    #include "stm32mp1xx_rcc.h"
    // MOSI对应的引脚输出高低电平的信号
    #define  MOSI_OUTPUT_H()	do{GPIOE->ODR |= (0x1 << 14);}while(0)
    #define  MOSI_OUTPUT_L()    do{GPIOE->ODR &= (~(0x1 << 14));}while(0)
    
    // 对应595芯片的锁存引脚输出高低电平
    #define  NSS_OUTPUT_H()	    do{GPIOE->ODR |= (0x1 << 11);}while(0)
    #define  NSS_OUTPUT_L()     do{GPIOE->ODR &= (~(0x1 << 11));}while(0)
    	
    // 时钟信号对应的引脚输出高低电平
    #define  SCK_OUTPUT_H()     do{GPIOE->ODR |= (0x1 << 12);}while(0)
    #define  SCK_OUTPUT_L()     do{GPIOE->ODR &= (~(0x1 << 12));}while(0)
    
    static delay_us(unsigned int us);
    
    
    /*
     * 函数功能: SPI初始化函数,推挽输出,高速,禁止上拉和下拉
     * 函数参数:无
     * 函数返回值:无
    */
    void SPI_init(void);
    /*
     * 函数功能:SPI发送数据的函数
     * 函数参数:dat : 要发送的数据
     * 函数返回值:无
     *
    */
    void SPI_write(unsigned char dat);
    
    
    #endif  // __SPI_H__
    
    
    • 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

    SPI.c

    #include "spi.h"
    /* 
    SPI4_NSS	PE11
    SPI4_SCK	PE12
    SPI4_MOSI	PE14
    SPI4_MISO	PE13
    */
    
    static delay_us(unsigned int us)
    {
    	int i = 0;
    	int j = 0;
    	for(i=0; i<us; i++)
    	{
    		for(j=0; j<10;j++);
    	}
    }
    
    void SPI_init(void)
    {
    	/* RCC时钟使能 */
    	RCC->MP_AHB4ENSETR |= (0x1<<4);
    
    	/* MOSI引脚配置 */
    	GPIOE->MODER &= (~(0x3 << 28));
    	GPIOE->MODER |= (0x1 << 28);
    	GPIOE->OTYPER &= (~(0x1 << 14));
    	GPIOE->OSPEEDR &=(~(0x3 << 28));
    	GPIOE->PUPDR &= (~(0x3 << 28));
    	/* MISO引脚配置 */
    	GPIOE->MODER &= (~(0x3 << 26));
    	GPIOE->OTYPER &= (~(0x1 << 13));
    	GPIOE->OSPEEDR &=(~(0x3 << 26));
    	GPIOE->PUPDR &= (~(0x3 << 28));
    	/* SCLK引脚配置 */
    	GPIOE->MODER &= (~(0x3 << 24));
    	GPIOE->MODER |= (0x1 << 24);
    	GPIOE->OTYPER &= (~(0x1 << 12));
    	GPIOE->OSPEEDR &=(~(0x3 << 24));
    	GPIOE->PUPDR &= (~(0x3 << 24));
    	/* CS引脚配置 */
    	GPIOE->MODER &= (~(0x3 << 22));
    	GPIOE->MODER |= (0x1 << 22);
    	GPIOE->OTYPER &= (~(0x1 << 11));
    	GPIOE->OSPEEDR &=(~(0x3 << 22));
    	GPIOE->PUPDR &= (~(0x3 << 22));
    
    	/* CS引脚拉低电平起始信号 */
    	NSS_OUTPUT_L();
    	/* SPI时钟线拉低 */
    	SCK_OUTPUT_L();
    	
    }
    
    void SPI_write(unsigned char dat)
    {
    	unsigned char i;
    	for(i=0; i<8; i++)
    	{
    		if(dat & 0x01)
    		{
    			MOSI_OUTPUT_H();
    		}
    		else
    		{
    			MOSI_OUTPUT_L();
    		}
    		dat>>=1;
    
    		/* 时钟线电平上升沿,数据写入 */
    		SCK_OUTPUT_L();
    		delay_us(5);
    		SCK_OUTPUT_H();
    		delay_us(5);
    	}
    }
    
    • 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

    SI7006.h

    #ifndef SI7006_H
    #define SI7006_H
    
    #include "i2c_driver.h"
    
    void delay_ms(unsigned int ms);
    
    void si7006_init(void);
    
    unsigned short si7006_read_hum_data(unsigned char slave_addr, 
    		unsigned char cmd_code);
    
    
    short si7006_read_temp_data(unsigned char slave_addr, 
    		unsigned char cmd_code);
    
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    SI7006.c

    #include "i2c_driver.h"
    #include "si7006.h"
    void delay_ms(unsigned int ms)
    {
    	unsigned int i = 0;
    	unsigned int j = 0;
    	for(i=0; i<ms; i++)
    	{
    		for(j=0; j<2000; j++);
    	}
    }
    /*
     * 函数名:si7006_init
     * 函数功能:SI7006芯片的初始化
     * 函数参数:无
     * 函数返回值:无
    */
    void si7006_init(void)
    {
    	I2C_Init();
    	I2C_Start();
    	I2C_SendByte(0x40 << 1 | 0);
    	I2C_SendByte(0xE6);
    	I2C_SendByte(0x3A);
    	I2C_Stop();
    }
    /*
     * 函数名:si7006_read_hum_data
     * 函数功能:读取SI7006的湿度转换结果
     * 函数参数:
     *     slave_addr : 从机地址
     *     cmd_code : 命令码
     * 函数返回值:湿度测量的数字量
    */
    unsigned short si7006_read_hum_data(unsigned char slave_addr, 
    		unsigned char cmd_code)
    {
    	unsigned short data;
    	unsigned char d_h;
    	unsigned char d_l;
    
    	I2C_Start();
    	I2C_SendByte(slave_addr << 1 | 0);
    	I2C_SendByte(cmd_code);
    	I2C_Start();
    	I2C_SendByte(slave_addr << 1 | 1);
    	delay_ms(2000);
    	d_h = I2C_ReadByte(ACK);
    	d_l = I2C_ReadByte(NACK);
    	I2C_Stop();
    	data = (d_h<<8)|d_l;
    
    	return data;
    }
    /*
     * 函数名:si7006_read_temp_data
     * 函数功能:读取SI7006的温度转换结果
     * 函数参数:
     *     slave_addr : 从机地址
     *     cmd_code : 命令码
     * 函数返回值:温度测量的数字量
    */
    short si7006_read_temp_data(unsigned char slave_addr, 
    		unsigned char cmd_code)
    {
    			short data;
    			unsigned char d_h;
    			unsigned char d_l;
    		
    			I2C_Start();
    			I2C_SendByte(slave_addr << 1 | 0);
    			I2C_SendByte(cmd_code);
    			I2C_Start();
    			I2C_SendByte(slave_addr << 1 | 1);
    			delay_ms(2000);
    			d_h = I2C_ReadByte(ACK);
    			d_l = I2C_ReadByte(NACK);
    			I2C_Stop();
    			data = (d_h<<8)|d_l;
    			
    			
    			return data;
    
    }
    
    
    
    • 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

    main.c

    
    #include "key_it.h"
    #include "uart.h"
    #include "beep.h"
    #include "si7006.h"
    #include "spi.h"
    
    
    
    void delay(volatile unsigned int d)
    {
    	int i,j;
    	for(i = 0; i < d;i++)
    		for (j = 0; j < 1800; j++);
    
    }
    
    static int num[10] = {0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xF6};
    static int data[5] = {0};
    int main(void)
    {
    	unsigned short hum;
    	unsigned short h_g;
    	unsigned short h_s;
    	short tem;
    	short t_g;
    	short t_s;
    	unsigned char i;
    	unsigned int j;
    	
    	si7006_init();
    	SPI_init();
    	
    
    	while(1)
    	{	
    		j = 800;
    		hum = si7006_read_hum_data(0x40, 0xE5);
    		tem = si7006_read_temp_data(0x40, 0xE3);
    		hum = 125*hum/65536-6;
    		tem = 175.72*tem/65536-46.85;
    
    		h_s = hum / 10;
    		h_g = hum % 10;
    		t_s = tem / 10;
    		t_g = tem % 10;
    
    		data[0] = num[t_s];
    		data[1] = num[t_g]+1;
    		data[2] = num[h_s];
    		data[3] = num[h_g];
    
    		printf("tem = %d\n\r", tem);
    		printf("hum = %d\n\r", hum);
    
    		while(j--)
    		{
    			for(i = 0; i < 5; i++)
    			{
    				SPI_write(0x80 >> i);
    				SPI_write(data[i]);
    				NSS_OUTPUT_L();
    				delay_ms(1);
    				NSS_OUTPUT_H();
    			}
    		}
    	}
    	
    	return 0;
    }
    
    
    • 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

    效果图

    在这里插入图片描述
    小数点仅作为分割数字使用,两边各自是两个整数
    在这里插入图片描述

  • 相关阅读:
    unity URP 利用particle system制作简单的shader交互
    虹科HiveMQ MQTT Broker如何支持平板电脑实现高效远程管理?
    http2.0/http3.0/rpc
    C语言:操作符详解(2)
    世界杯“引爆”东南亚电商狂潮,电商人如何选品和营销?
    程序员:你如何写可重复执行的SQL语句?
    jmeter理论
    一朵华为云,如何做好百模千态?
    大型语言模型LLM的数据管理与应用
    时间复杂度与空间复杂度
  • 原文地址:https://blog.csdn.net/m0_72847002/article/details/133868944