打印
[综合信息]

SWM260模拟IIC

[复制链接]
382|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2023-2-15 09:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
模拟IIC的程序代码到处都是,我用的一个在ST的板子上已经验证过的IIC程序移植到SWM260上;

结果,怎么都出不来想要的结果,示波器看波形也是对的,百思不得其解,查了好久好久,最后找到了华芯微特官方给的GPIO初始化操作的的函数上了;

SWM260的GPIO初始化函数如下:

/******************************************************************************************************************************************
* 函数名称: GPIO_Init()
* 功能说明:        引脚初始化,包含引脚方向、上拉、下拉、开漏
* 输    入: GPIO_TypeDef * GPIOx            指定GPIO端口,有效值包括GPIOA、GPIOB、GPIOC、GPIOD
*                        uint32_t n                       指定GPIO引脚,有效值包括PIN0、PIN1、PIN2、... ... PIN14、PIN15
*                        uint32_t dir               引脚方向,0 输入        1 输出
*                        uint32_t pull_up           上拉使能
*                        uint32_t pull_down           下拉使能
*                        uint32_t open_drain           开漏使能
* 输    出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void GPIO_Init(GPIO_TypeDef * GPIOx, uint32_t n, uint32_t dir, uint32_t pull_up, uint32_t pull_down, uint32_t open_drain)
{
        switch((uint32_t)GPIOx)
        {
        case ((uint32_t)GPIOA):
                SYS->CLKEN0 |= (0x01 << SYS_CLKEN0_GPIOA_Pos);
               
                PORT_Init(PORTA, n, 0, 1);                        //PORTA.PINn引脚配置为GPIO功能,数字输入开启
                if(dir == 1)
                {                       
                        GPIOA->DIR |= (0x01 << n);
                }
                else
                {
                        GPIOA->DIR &= ~(0x01 << n);
                }
               
                if(pull_up == 1)     PORT->PORTA_PULLU |=  (1 << n);
                else                 PORT->PORTA_PULLU &= ~(1 << n);
                if(pull_down == 1)   PORT->PORTA_PULLD |=  (1 << n);
                else                 PORT->PORTA_PULLD &= ~(1 << n);
                if(open_drain == 1)  PORT->PORTA_OPEND |=  (1 << n);
                else                 PORT->PORTA_OPEND &= ~(1 << n);
                break;
       
        case ((uint32_t)GPIOB):
                SYS->CLKEN0 |= (0x01 << SYS_CLKEN0_GPIOB_Pos);
               
                PORT_Init(PORTB, n, 0, 1);
                if(dir == 1)
                {                       
                        GPIOB->DIR |=  (0x01 << n);
                }
                else
                {
                        GPIOB->DIR &= ~(0x01 << n);
                }
               
                if(pull_up == 1)     PORT->PORTB_PULLU |=  (1 << n);
                else                 PORT->PORTB_PULLU &= ~(1 << n);
                if(pull_down == 1)   PORT->PORTB_PULLD |=  (1 << n);
                else                 PORT->PORTB_PULLD &= ~(1 << n);
                if(open_drain == 1)  PORT->PORTB_OPEND |=  (1 << n);
                else                 PORT->PORTB_OPEND &= ~(1 << n);
                break;
       
        case ((uint32_t)GPIOC):
                SYS->CLKEN0 |= (0x01 << SYS_CLKEN0_GPIOC_Pos);
               
                PORT_Init(PORTC, n, 0, 1);
                if(dir == 1)
                {                       
                        GPIOC->DIR |=  (0x01 << n);
                }
                else
                {
                        GPIOC->DIR &= ~(0x01 << n);
                }
               
                if(pull_up == 1)     PORT->PORTC_PULLU |=  (1 << n);
                else                 PORT->PORTC_PULLU &= ~(1 << n);
                if(pull_down == 1)   PORT->PORTC_PULLD |=  (1 << n);
                else                 PORT->PORTC_PULLD &= ~(1 << n);
                if(open_drain == 1)  PORT->PORTC_OPEND |=  (1 << n);
                else                 PORT->PORTC_OPEND &= ~(1 << n);
                break;
       
        case ((uint32_t)GPIOD):
                SYS->CLKEN0 |= (0x01 << SYS_CLKEN0_GPIOD_Pos);
               
                PORT_Init(PORTD, n, 0, 1);
                if(dir == 1)
                {                       
                        GPIOD->DIR |=  (0x01 << n);
                }
                else
                {
                        GPIOD->DIR &= ~(0x01 << n);
                }
               
                if(pull_up == 1)     PORT->PORTD_PULLU |=  (1 << n);
                else                 PORT->PORTD_PULLU &= ~(1 << n);
                if(pull_down == 1)   PORT->PORTD_PULLD |=  (1 << n);
                else                 PORT->PORTD_PULLD &= ~(1 << n);
                if(open_drain == 1)  PORT->PORTD_OPEND |=  (1 << n);
                else                 PORT->PORTD_OPEND &= ~(1 << n);
                break;
        }
}



都是对寄存器的操作封装,问题部分如下:



IIC初始化时IO需要设置为开漏输出,习惯上还要设置上拉,但该初始化语句采用的else if会导致初始化时只执行上拉,不执行开漏输出,导致模拟IIC失败;

附SWM260的模拟IIC代码,测试可用

/******************************************************************************
* @ File name --> iic.h
* @ Brief     --> MCU模拟IIC通讯函数
* @           --> 要改变传输频率,请修改延时函数中的数值即可
******************************************************************************/

#ifndef _iic_h_
#define _iic_h_

/******************************************************************************
                                 外部函数头文件                        
******************************************************************************/
#include "SWM260.h"
#include "SWM260_gpio.h"
#include        "SWM260_port.h"

/******************************************************************************
                                 外部引脚修改区                        
******************************************************************************/


#if 0
/*  IIC_SCL时钟端口、引脚定义 */
#define IIC_SCL_PORT                         GPIOB   
#define IIC_SCL_PIN                         PIN11
/*  IIC_SDA时钟端口、引脚定义 */
#define IIC_SDA_PORT                         GPIOB  
#define IIC_SDA_PIN                         PIN10
#else
/*  IIC_SCL时钟端口、引脚定义 */
#define IIC_SCL_PORT                         GPIOA   
#define IIC_SCL_PIN                         PIN10
/*  IIC_SDA时钟端口、引脚定义 */
#define IIC_SDA_PORT                         GPIOA
#define IIC_SDA_PIN                         PIN11

#endif



#define IIC_SCL_High                 GPIO_SetBit(IIC_SCL_PORT,IIC_SCL_PIN)// 输出高电平
#define IIC_SCL_Low                 GPIO_ClrBit(IIC_SCL_PORT,IIC_SCL_PIN)// 输出低电平

#define IIC_SDA_High                 GPIO_SetBit(IIC_SDA_PORT,IIC_SDA_PIN)// 输出高电平
#define IIC_SDA_Low                 GPIO_ClrBit(IIC_SDA_PORT,IIC_SDA_PIN)// 输出低电平
#define IIC_SDA_Read                GPIO_GetBit(IIC_SDA_PORT,IIC_SDA_PIN)



/******************************************************************************
                             对于低速晶振的支持
                     是否使用延时函数进行调整通讯频率
******************************************************************************/

#define _USER_DELAY_CLK                                        0        //定义了则使用延时调整通讯频率
                                                                                        //0:不使用延时函数调整通讯频率,对于低速MCU时候用
                                                                                        //1:使用延时函数调整通讯频率,对于高速MCU时候用

/******************************************************************************
                                位带操作
******************************************************************************/
//#define IIC_SCL                                        PBout(6)
//#define IIC_SDA                                        PBout(7)        //IIC发送数据用
//#define IN_SDA                                        PBin(7)            //IIC读取数据用


/******************************************************************************
                               通讯频率延时函数
                    需要调整通讯频率的请修改此函数值即可
******************************************************************************/

#if        _USER_DELAY_CLK==1        //定义了则使用

        #define IIC_Delay()                 delay_us(2) //要改变请修改delay_us()中的数值即可

#endif

/******************************************************************************
                                 外部功能函数
******************************************************************************/

void IIC_GPIO_Init(void);            //GPIO初始化

void IIC_Start(void);                //IIC启动

void IIC_Stop(void);                //IIC停止

void IIC_Ack(uint8_t a);                    //主机向从机发送应答信号

uint8_t IIC_Write_Byte(uint8_t dat);            //向IIC总线发送一个字节数据

uint8_t IIC_Read_Byte(void);                //从IIC总线上读取一个字节数据



#endif  /* end iic.h */





#include "iic.h"

void delay_us(uint16_t ms)
{
        uint16_t i;
        while(ms--)
                for(i=0;i<6;i++)        __NOP();        //等待
}
/******************************************************************************
* Function Name --> IIC_GPIO_Init
* Description   --> GPIO初始化
* Input         --> none
* Output        --> none
* Reaturn       --> none
GPIO_InitStruct.Pin = OUT2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(OUT2_GPIO_Port, &GPIO_InitStruct);
******************************************************************************/
void IIC_GPIO_Init(void)
{
//        PORT_Init(PORTB, IIC_SCL_PIN, PORTB_PIN11_GPIO, 1);
//        PORT_Init(PORTB, IIC_SDA_PIN, PORTB_PIN10_GPIO, 1);               
//       
        GPIO_Init(IIC_SCL_PORT, IIC_SCL_PIN, 1, 0, 0, 1);        //PC12接LED                引脚方向,0输入,1输出;上拉使能;下拉使能;开漏使能
        GPIO_Init(IIC_SDA_PORT, IIC_SDA_PIN, 1, 0, 0, 1);        //PC12接LED                引脚方向,0输入,1输出;上拉使能;下拉使能;开漏使能
       
       
//        PORT_Init(PORTB, PIN11, PORTB_PIN11_I2C4_SCL, 1);        //GPIOB.11配置为I2C4 SCL引脚
//        PORT->PORTB_PULLU |= (1 << PIN11);                                        //必须使能上拉,用于模拟开漏
//        PORT_Init(PORTB, PIN10, PORTB_PIN10_I2C4_SDA, 1);        //GPIOB.10配置为I2C4 SDA引脚
//        PORT->PORTB_PULLU |= (1 << PIN10);                                        //必须使能上拉,用于模拟开漏       
       
        IIC_SDA_High;  //置IIC总线空闲
        IIC_SCL_High;
}

/******************************************************************************
* Function Name --> SDA_OUT
* Description   --> SDA输出配置         
******************************************************************************/
void IIC_SDA_OUT(void)
{

        GPIO_Init(IIC_SDA_PORT, IIC_SDA_PIN, 1, 0, 0, 1);        //PC12接LED                引脚方向,0输入,1输出;上拉使能;下拉使能;开漏使能
       
//                SYS->CLKEN0 |= (0x01 << SYS_CLKEN0_GPIOB_Pos);
//                IIC_SDA_PORT->DIR |=  0x400;                                //输出
//        GPIOB->DIR |=  (0x01 << IIC_SDA_PIN);                                //输出
//  GPIOB->DIR &= ~(0x01 << IIC_SDA_PIN);                        //输入
}

/******************************************************************************
* Function Name --> SDA_IN
* Description   --> SDA输入配置
******************************************************************************/
void IIC_SDA_IN(void)
{
//        GPIOB->DIR &= ~(0x01 << IIC_SDA_PIN);                        //输入
        GPIO_Init(IIC_SDA_PORT, IIC_SDA_PIN, 0, 0, 0, 1);        //PC12接LED                引脚方向,0输入,1输出;上拉使能;下拉使能;开漏使能
}

/******************************************************************************
* Function Name --> IIC启动
* Description   --> SCL高电平期间,SDA由高电平突变到低电平时启动总线
*                   SCL: __________
*                                  \__________
*                   SDA: _____
*                             \_______________
******************************************************************************/
void IIC_Start(void)
{
        IIC_SDA_OUT();        //设置成输出

        IIC_SDA_High;        //为SDA下降启动做准备
        IIC_SCL_High;        //在SCL高电平时,SDA为下降沿时候总线启动
       
#if _USER_DELAY_CLK==1  /* 定义了则使用延时函数来改变通讯频率 */
       
        IIC_Delay();
        IIC_SDA_Low;        //突变,总线启动
        IIC_Delay();
        IIC_SCL_Low;
        IIC_Delay();

#else  /* 否则不使用延时函数改变通讯频率 */
       
        IIC_SDA_Low;        //突变,总线启动
        IIC_SCL_Low;

#endif  /* end __USER_DELAY_CLK */
}

/******************************************************************************
* Function Name --> IIC停止
* Description   --> SCL高电平期间,SDA由低电平突变到高电平时停止总线
*                   SCL: ____________________
*                                  __________
*                   SDA: _________/
* Input         --> none
* Output        --> none
* Reaturn       --> none
******************************************************************************/
void IIC_Stop(void)
{
        IIC_SDA_OUT();        //设置成输出

        IIC_SDA_Low;        //为SDA上升做准备
       
#if _USER_DELAY_CLK==1  /* 定义了则使用延时函数来改变通讯频率 */

        IIC_Delay();
        IIC_SCL_High;        //在SCL高电平时,SDA为上升沿时候总线停止
        IIC_Delay();
        IIC_SDA_High;        //突变,总线停止
        IIC_Delay();

#else  /* 否则不使用延时函数改变通讯频率 */

        IIC_SCL_High;        //在SCL高电平时,SDA为上升沿时候总线停止
        IIC_SDA_High;        //突变,总线停止

#endif  /* end __USER_DELAY_CLK */
}

/******************************************************************************
* Function Name --> 主机向从机发送应答信号
* Description   --> none
* Input         --> a:应答信号
*                      0:应答信号
*                      1:非应答信号
* Output        --> none
* Reaturn       --> none
******************************************************************************/
void IIC_Ack(uint8_t a)
{
        IIC_SDA_OUT();        //设置成输出

        if(a)        IIC_SDA_High;        //放上应答信号电平
        else        IIC_SDA_Low;
       
#if _USER_DELAY_CLK==1  /* 定义了则使用延时函数来改变通讯频率 */

        IIC_Delay();
        IIC_SCL_High;        //为SCL下降做准备
        IIC_Delay();
        IIC_SCL_Low;        //突变,将应答信号发送过去
        IIC_Delay();

#else  /* 否则不使用延时函数改变通讯频率 */

        IIC_SCL_High;        //为SCL下降做准备
        IIC_SCL_Low;        //突变,将应答信号发送过去

#endif  /* end __USER_DELAY_CLK */
}

/******************************************************************************
* Function Name --> 向IIC总线发送一个字节数据
* Description   --> none
* Input         --> dat:要发送的数据
* Output        --> none
* Reaturn       --> ack:返回应答信号
******************************************************************************/
uint8_t IIC_Write_Byte(uint8_t dat)
{
        uint8_t i;
        uint8_t iic_ack=0;        //iic应答标志

        IIC_SDA_OUT();        //设置成输出

        for(i = 0;i < 8;i++)
        {
                if(dat & 0x80)        IIC_SDA_High;        //判断发送位,先发送高位
                else        IIC_SDA_Low;

#if _USER_DELAY_CLK==1  /* 定义了则使用延时函数来改变通讯频率 */
                       
                IIC_Delay();
                IIC_SCL_High;        //为SCL下降做准备
                IIC_Delay();
                IIC_SCL_Low;        //突变,将数据位发送过去
                dat<<=1;        //数据左移一位
        }        //字节发送完成,开始接收应答信号

        IIC_SDA_High;        //释放数据线

        IIC_SDA_IN();        //设置成输入

        IIC_Delay();
        IIC_SCL_High;        //为SCL下降做准备
        IIC_Delay();

#else  /* 否则不使用延时函数改变通讯频率 */

                IIC_SCL_High;        //为SCL下降做准备
                IIC_SCL_Low;        //突变,将数据位发送过去
                dat<<=1;        //数据左移一位
        }        //字节发送完成,开始接收应答信号

        IIC_SDA_High;        //释放数据线

        IIC_SDA_IN();        //设置成输入

        IIC_SCL_High;        //为SCL下降做准备

#endif  /* end __USER_DELAY_CLK */
       
        iic_ack |= IIC_SDA_Read;        //读入应答位
        IIC_SCL_Low;
        return iic_ack;        //返回应答信号
}

/******************************************************************************
* Function Name --> 从IIC总线上读取一个字节数据
* Description   --> none
* Input         --> none
* Output        --> none
* Reaturn       --> x:读取到的数据
******************************************************************************/
uint8_t IIC_Read_Byte(void)
{
        uint8_t i;
        uint8_t x=0;

        IIC_SDA_High;        //首先置数据线为高电平

        IIC_SDA_IN();        //设置成输入

        for(i = 0;i < 8;i++)
        {
                x <<= 1;        //读入数据,高位在前

#if _USER_DELAY_CLK==1  /* 定义了则使用延时函数来改变通讯频率 */

                IIC_Delay();
                IIC_SCL_High;        //突变
                IIC_Delay();
               
                if(IIC_SDA_Read)        x |= 0x01;        //收到高电平

                IIC_SCL_Low;
                IIC_Delay();
        }        //数据接收完成

#else  /* 否则不使用延时函数改变通讯频率 */

                IIC_SCL_High;        //突变
               
                if(IIC_SDA_Read)        x |= 0x01;        //收到高电平

                IIC_SCL_Low;
        }        //数据接收完成

#endif  /* end __USER_DELAY_CLK */

        IIC_SCL_Low;

        return x;        //返回读取到的数据
}


————————————————
版权声明:本文为CSDN博主「QAQlfk」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40307946/article/details/110367264

使用特权

评论回复

相关帖子

沙发
chenqianqian| | 2023-2-15 09:51 | 只看该作者
原来是搬运过来的哦

使用特权

评论回复
板凳
updownq| | 2023-3-7 13:44 | 只看该作者
模拟iic只是便于移植了。              

使用特权

评论回复
地板
i1mcu| | 2023-3-7 19:46 | 只看该作者
SWM260最大的读写速度是多少?

使用特权

评论回复
5
chenci2013| | 2023-3-7 20:49 | 只看该作者
为什么不使用硬件IIC?              

使用特权

评论回复
6
usysm| | 2023-3-7 20:54 | 只看该作者
这个需要改IIC的SDA的方向吗?

使用特权

评论回复
7
chenjun89| | 2023-3-21 08:12 | 只看该作者
模拟IIC效率不行

使用特权

评论回复
8
小夏天的大西瓜| | 2023-3-28 17:08 | 只看该作者
好移植,效率高吗?

使用特权

评论回复
9
华芯微特FAE| | 2023-3-29 09:45 | 只看该作者
i1mcu 发表于 2023-3-7 19:46
SWM260最大的读写速度是多少?

最高可达400K

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1360

主题

13960

帖子

8

粉丝