123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509 |
- /************************************************************************************************/
- /**
- * @file i2c_bsp.c
- * @author MCU Ecosystem Development Team + 我
- * @brief I2C BSP驱动函数,使用GPIO模拟I2C主模式,实现I2C主模式通信协议。
- *
- *
- **************************************************************************************************
- * @attention
- * Copyright (c) CEC Huada Electronic Design Co.,Ltd. All rights reserved.
- *
- **************************************************************************************************
- */
- #include "i2c_bsp.h"
-
- /*
- 华大i2c_bsp.c 模块说明
- 注意:本模块为了更适合使用,已经进行了修改了,标准100k iic通信
- 注意:延时函数一定要保证1us为基本单位: i2c_delay_time(uint32_t delay_time) 这延时必须要实现1us 在不同的系统频率下
- 标准100k,iic通信时序要求;
- 1.数据保存时间: 5us及以上
- 2.数据建立时间: 5us及以上
- 3.低电平时间: 5us及以上
- 4.高电平时间: 5us及以上
- 注意:模拟的一般只适合标准iic 100k的通信速率. 要根据系统时钟的修改,验证i2c_delay_time(1)必须是1us
-
- 使用方法:
- uint8_t err_flag = 0;
- uint8_t BULL[8] = {0X00, OX11, 0X22 , 0X33 , 0X44, 0X55 , 0X66 , 0X77};
-
- void my_iic_err_call(void){
-
- err_flag = 1;
- }
- int main(void){
-
- SN_SYSCLK_set(SYSCLK_48MHZ);
- std_delay_init();
- SN_IIC_IO_set(IIC_SCL_PB3 ,IIC_SCL_PB4 ,IIC_PULLUP); //设置iic通信引脚
- SN_IIC_ERROR_call(my_iic_err_call); //设置错误处理函数
- SN_IIC_slave(0x5a); //设置通信从机地址
-
- while(1){
- std_delayms(500);
- bsp_i2c_master_send(BULL,8); //发送数据给从机0x5a
- std_delayms(500);
- bsp_i2c_master_receive(BULL,8); //从0x5a从机中接收数据
- }
- }
- */
- __IO uint8_t SLAVE_ADDRESS = 0x00 ; //全局变量,从机id号码
- GPIO_t * I2C_PIN_PORT1 = NULL; //SCL的端口
- GPIO_t * I2C_PIN_PORT2 = NULL; //SDA的端口
- __IO uint16_t SCL_PIN = 0x0000000; //SCL引脚
- __IO uint16_t SDA_PIN = 0x0000000; //SDA引脚
- void (* SN_IIC_error_call ) (void) = NULL; //iic通信错误处理函数指针
- /*
- 函数: SN_IIC_IO_set(uint8_t SCL_PIN_x ,uint8_t SDA_PIN_x)
- 功能: 设置i2c_bsp模块的io引脚使用
- 参数: SCL_PIN_x
- @IIC_SCL_PA0
- @IIC_SCL_PA1
- @IIC_SCL_PA2 (仿真线)
- @IIC_SCL_PA3
- @IIC_SCL_PA4
- @IIC_SCL_PA5
- @IIC_SCL_PA6
- @IIC_SCL_PA7
-
- @IIC_SCL_PB0
- @IIC_SCL_PB1
- @IIC_SCL_PB2
- @IIC_SCL_PB3
- @IIC_SCL_PB4
- @IIC_SCL_PB5
- @IIC_SCL_PB6 (仿真线)
- @IIC_SCL_PB7
-
- @IIC_SCL_PC0 (复位线,必须修改选项字节才可以使用)
- @IIC_SCL_PC1
-
- 参数: SDA_PIN_x
- @IIC_SDA_PA0
- @IIC_SDA_PA1
- @IIC_SDA_PA2 (仿真线)
- @IIC_SDA_PA3
- @IIC_SDA_PA4
- @IIC_SDA_PA5
- @IIC_SDA_PA6
- @IIC_SDA_PA7
-
- @IIC_SDA_PB0
- @IIC_SDA_PB1
- @IIC_SDA_PB2
- @IIC_SDA_PB3
- @IIC_SDA_PB4
- @IIC_SDA_PB5
- @IIC_SDA_PB6 (仿真线)
- @IIC_SDA_PB7
-
- @IIC_SDA_PC0 (复位线,必须修改选项字节才可以使用)
- @IIC_SDA_PC1
-
- 参数: 是否使用内部上拉
- @IIC_PULLUP_NULL //不使用内部上拉,用户自己在iic总线加上拉电阻
- @IIC_PULLUP //使用内部30k上拉电阻 100k标准协议不影响
- 返回:无
- */
- void SN_IIC_IO_set(uint8_t SCL_PIN_x ,uint8_t SDA_PIN_x ,uint8_t PULLUP )
- {
-
- uint32_t GPIO_PULLUP_x = 0;
- GPIO_t * GPIO_x = NULL;
- uint16_t GPIO_PIN_x = 0;
- uint32_t RCC_PERIPH_CLK_GPIO_x = 0;
-
- std_gpio_init_t gpio_config = {0};
-
- //是否使用内部上拉电阻
- GPIO_PULLUP_x = (PULLUP) ? GPIO_PULLUP : GPIO_NOPULL ;
-
-
- //处理SCL
-
- GPIO_x = (SCL_PIN_x < 9)? GPIOA : (SCL_PIN_x < 16) ? GPIOB : GPIOC ;
- RCC_PERIPH_CLK_GPIO_x = (SCL_PIN_x < 9)? RCC_PERIPH_CLK_GPIOA : (SCL_PIN_x < 16) ? RCC_PERIPH_CLK_GPIOB : RCC_PERIPH_CLK_GPIOC ;
- GPIO_PIN_x = (SCL_PIN_x < 9) ? (GPIO_PIN_0 << (SCL_PIN_x - 1)) : (SCL_PIN_x < 16) ? ( GPIO_PIN_0 << (SCL_PIN_x - 9)) : ( GPIO_PIN_0 << (SCL_PIN_x - 17)) ;
-
- //设置全局 scl引脚
- I2C_PIN_PORT1 = GPIO_x ;
- SCL_PIN = GPIO_PIN_x ;
-
- std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIO_x);
- gpio_config.pin = GPIO_PIN_x;
- gpio_config.mode = GPIO_MODE_OUTPUT;
- gpio_config.output_type = GPIO_OUTPUT_OPENDRAIN;
- gpio_config.pull = GPIO_PULLUP_x ;
- std_gpio_init(GPIO_x, &gpio_config);
-
- //处理SDA
-
- GPIO_x = (SDA_PIN_x < 9)? GPIOA : (SDA_PIN_x < 16) ? GPIOB : GPIOC ;
- RCC_PERIPH_CLK_GPIO_x = (SDA_PIN_x < 9)? RCC_PERIPH_CLK_GPIOA : (SDA_PIN_x < 16) ? RCC_PERIPH_CLK_GPIOB : RCC_PERIPH_CLK_GPIOC ;
- GPIO_PIN_x = (SDA_PIN_x < 9) ? (GPIO_PIN_0 << (SDA_PIN_x - 1)) : (SDA_PIN_x < 16) ? ( GPIO_PIN_0 << (SDA_PIN_x - 9)) : ( GPIO_PIN_0 << (SDA_PIN_x - 17)) ;
-
- //设置全局 scl引脚
- I2C_PIN_PORT2 = GPIO_x ;
- SDA_PIN = GPIO_PIN_x ;
-
-
- std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIO_x);
- gpio_config.pin = GPIO_PIN_x;
- gpio_config.mode = GPIO_MODE_OUTPUT;
- gpio_config.output_type = GPIO_OUTPUT_OPENDRAIN;
- std_gpio_init(GPIO_x, &gpio_config);
- }
- /*
- 函数: SN_IIC_slave(uint16_t iic_slave_id )
- 功能: 设置通信从机ic
- 参数: 7位 或 10位 从机id
- 返回; 无
- */
- void SN_IIC_slave(uint8_t iic_slave_id ){
-
- SLAVE_ADDRESS = iic_slave_id ;
- }
- /*
- 函数: SN_IIC_ERROR_call(void (*error_call) (void) )
- 功能: 设置通信错误处理函数
- 参数: 错误回调函数 用户自己处理的情况: 1.发出地址没有应答 2,接收数据没有应答 3.超时没有应答
- 返回; 无
- */
- void SN_IIC_ERROR_call(void (*error_call) (void)){
- SN_IIC_error_call = error_call ;
- }
- /**
- * @brief 异常处理
- * @retval 无
- */
- void error_process(void)
- {
- /* 用户添加异常处理流程 */
- SN_IIC_error_call();
- }
- /**
- * @brief I2C延时函数
- * @param delay_time 延时计数值
- * @note 用户可更改延时计数值来调整I2C的通信速率 注意:软件就延时必须要看系统频率,测试一下这个时间在当前系统频率下是否正确
- * @retval 无
- 注意:必须实现1us的基本单位
- */
- void i2c_delay_time(uint32_t delay_time)
- {
- //------------------------------------软件延时处理--------
- uint32_t delay_cnt;
-
- for(delay_cnt=delay_time; delay_cnt>0; delay_cnt--);
-
-
- }
- /**
- * @brief I2C生成起始位
- * @retval 无
- */
- static void bsp_i2c_generate_start(void)
- {
- /* 切换输出模式前固定电平状态以避免毛刺 */
- std_gpio_set_pin(I2C_PIN_PORT1, SCL_PIN );
- std_gpio_set_pin(I2C_PIN_PORT2, SDA_PIN );
-
- /* 设置SDA为输出模式 */
- std_gpio_set_pin_mode(I2C_PIN_PORT2, SDA_PIN, GPIO_MODE_OUTPUT);
- i2c_delay_time(CLK_DELAY);
- std_gpio_reset_pin(I2C_PIN_PORT2, SDA_PIN);
- i2c_delay_time(CLK_DELAY);
- std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN);
- }
- /**
- * @brief I2C生成停止位
- * @retval 无
- */
- static void bsp_i2c_generate_stop(void)
- {
- /* 切换输出模式前固定电平状态以避免毛刺 */
- std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN );
- std_gpio_reset_pin(I2C_PIN_PORT2, SDA_PIN );
- /* 设置SDA为输出模式 */
- std_gpio_set_pin_mode(I2C_PIN_PORT2, SDA_PIN, GPIO_MODE_OUTPUT);
- i2c_delay_time(CLK_DELAY);
- std_gpio_set_pin(I2C_PIN_PORT1, SCL_PIN);
- i2c_delay_time(CLK_DELAY);
- std_gpio_set_pin(I2C_PIN_PORT2, SDA_PIN);
- }
- /**
- * @brief I2C生成ACK/NACK
- * @param ack_type ACK类型
- * @arg RET_ACK: 主机发送ACK
- * @arg RET_NACK: 主机发送NACK
- * @retval 无
- */
- static void bsp_i2c_generate_ack(uint32_t ack_type)
- {
- /* 切换输出模式前根据返回ACK/NACK固定电平状态以避免毛刺 */
- if(ack_type == RET_ACK)
- {
- std_gpio_reset_pin(I2C_PIN_PORT2, SDA_PIN);
- }
- else
- {
- std_gpio_set_pin(I2C_PIN_PORT2, SDA_PIN);
- }
-
- /* 设置SDA为输出模式 */
- std_gpio_set_pin_mode(I2C_PIN_PORT2, SDA_PIN, GPIO_MODE_OUTPUT);
-
- i2c_delay_time(CLK_DELAY);
- std_gpio_set_pin(I2C_PIN_PORT1, SCL_PIN);
- i2c_delay_time(CLK_DELAY);
- std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN);
- }
- /**
- * @brief I2C主模式发送一个字节数据
- * @param data 发送数据
- * @retval uint32_t 返回从机ACK状态
- * @arg RET_ACK: 从机返回ACK
- * @arg RET_NACK: 从机返回NACK
- */
- static uint32_t bsp_i2c1_master_send_byte(uint8_t send_data)
- {
- uint32_t bit_cnt = 0;
- uint32_t ack_type = 0;
-
- /* 切换输出模式前固定电平状态以避免毛刺 */
- if (send_data & 0x80)
- {
- std_gpio_set_pin(I2C_PIN_PORT2, SDA_PIN);
- }
- else
- {
- std_gpio_reset_pin(I2C_PIN_PORT2, SDA_PIN);
- }
-
- /* 设置SDA为输出模式 */
- std_gpio_set_pin_mode(I2C_PIN_PORT2, SDA_PIN, GPIO_MODE_OUTPUT);
-
- /* 发送8bit数据 */
- for (bit_cnt=0; bit_cnt < 8; bit_cnt++)
- {
- if ((send_data << bit_cnt) & 0x80)
- {
- std_gpio_set_pin(I2C_PIN_PORT2, SDA_PIN);
- }
- else
- {
- std_gpio_reset_pin(I2C_PIN_PORT2, SDA_PIN);
- }
- i2c_delay_time(CLK_DELAY);
- std_gpio_set_pin(I2C_PIN_PORT1, SCL_PIN);
- i2c_delay_time(CLK_DELAY);
- std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN);
- }
-
- /* 判断从机返回ACK */
- std_gpio_set_pin_mode(I2C_PIN_PORT2, SDA_PIN, GPIO_MODE_INPUT);
- i2c_delay_time(CLK_DELAY);
- std_gpio_set_pin(I2C_PIN_PORT1, SCL_PIN);
- i2c_delay_time(ACK_DELAY);
-
- for (bit_cnt=0; bit_cnt < 5; bit_cnt++)
- {
- if (std_gpio_get_input_pin(I2C_PIN_PORT2, SDA_PIN) == false)
- {
- ack_type = RET_ACK;
- }
- else
- {
- ack_type = RET_NACK;
- break;
- }
- }
- std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN);
- i2c_delay_time(CLK_DELAY);
-
- return ack_type;
- }
- /**
- * @brief I2C主模式接收一个字节数据
- * @retval uint8_t 接收数据
- */
- static uint8_t bsp_i2c1_master_receive_byte(void)
- {
- uint32_t bit_cnt = 0;
- uint8_t receive_data = 0;
-
- /* 设置SDA为输入状态 */
- std_gpio_set_pin_mode(I2C_PIN_PORT2, SDA_PIN, GPIO_MODE_INPUT);
-
- /* 接收8bit数据 */
- for (bit_cnt=0; bit_cnt<8; bit_cnt++)
- {
- std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN);
- i2c_delay_time(CLK_DELAY);
- std_gpio_set_pin(I2C_PIN_PORT1, SCL_PIN);
- i2c_delay_time(CLK_DELAY);
-
- receive_data = receive_data << 1;
- if (std_gpio_get_input_pin(I2C_PIN_PORT2, SDA_PIN) == true)
- {
- receive_data += 1;
- }
- }
- std_gpio_reset_pin(I2C_PIN_PORT1, SCL_PIN);
- i2c_delay_time(CLK_DELAY);
-
- return receive_data;
- }
- //-------------------------------------------------------------------------------------------------------------------------------------------
- /**
- * @brief I2C主模式发送数据流程
- * @retval 无
- */
- void bsp_i2c_master_send(uint8_t * g_tx_buffer , uint16_t BUFF_SIZE)
- {
- uint32_t ack_type;
- uint32_t index;
-
- /* 发送start位 */
- bsp_i2c_generate_start();
-
- /* 发送从机地址及写请求 */
- ack_type = bsp_i2c1_master_send_byte(SLAVE_ADDRESS | REQ_WRITE);
- if (ack_type != RET_ACK)
- {
- error_process();
- }
-
- /* 地址匹配转数据发送延时 */
- /* 用户可根据实际从机地址匹配后的时序进行调整 */
- i2c_delay_time(USER_DELAY);
-
- /* 发送数据 */
- for (index=0; index<BUFF_SIZE; index++)
- {
- ack_type = bsp_i2c1_master_send_byte(g_tx_buffer[index]);
- if (ack_type != RET_ACK)
- {
- error_process();
- }
- }
-
- /* 发送stop位 */
- bsp_i2c_generate_stop();
- }
- /**
- * @brief I2C主模式接收数据
- * @retval 无
- */
- void bsp_i2c_master_receive(uint8_t * g_rx_buffer , uint16_t BUFF_SIZE)
- {
- uint32_t ack_type;
- uint32_t index;
-
- /* 发送start位 */
- bsp_i2c_generate_start();
-
- /* 发送从机地址及读请求 */
- ack_type = bsp_i2c1_master_send_byte(SLAVE_ADDRESS | REQ_READ);
- if (ack_type != RET_ACK)
- {
- error_process();
- }
-
- /* 地址匹配转数据接收延时 */
- /* 用户可根据实际从机地址匹配后的时序进行调整 */
- i2c_delay_time(USER_DELAY);
-
- /* 接收数据 */
- for (index=0; index<BUFF_SIZE-1; index++)
- {
- g_rx_buffer[index] = bsp_i2c1_master_receive_byte();
- bsp_i2c_generate_ack(RET_ACK);
- }
- g_rx_buffer[index] = bsp_i2c1_master_receive_byte();
- bsp_i2c_generate_ack(RET_NACK);
-
- /* 发送stop位 */
- bsp_i2c_generate_stop();
- }
|