查看: 3135|回复: 6

徐州工程学院(开发手册)STM32之驱动移植杂记(2)

[复制链接]
  • TA的每日心情
    开心
    2013-7-2 13:29
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2013-8-20 13:11:44 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 shen2008jie 于 2013-8-20 13:15 编辑

    好了接着昨天的写了的宏定义和一个初始化函数:
    /* 宏定义 -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- ----- */
    //IO方向设置宏定义
    #define    SDA _pin   1
    #define    GPIOXX   GPIOD
    #define SDA_IN()     {GPIOXX-> MODER &=~((0x00000003)<<(2* pinpos )); GPIOXX-> MODER |= (((uint32_t) 0x00 ) << ( SDA _pin * 2)); }  //这里GPIO XX-> MODER选的是D的
    #define SDA_OUT()   {GPIOXX-> MODER &=~((0x00000003)<<(2* pinpos )); GPIOXX-> MODER |= (((uint32_t) 0x01 ) << ( SDA _pin * 2)); }  //这里GPIO XX-> MODER选的是D的
    //IO操作函数宏定义         
    #define IIC_SCL_1    GPIO_SetBits(GPIOD, GPIO_Pin_0)
    #define IIC_SCL_0    GPIO_ResetBits(GPIOD, GPIO_Pin_0)
    #define IIC_SDA_1    GPIO_SetBits(GPIOD, GPIO_Pin_1)
    #define IIC_SDA_0    GPIO_ResetBits(GPIOD, GPIO_Pin_1)  //输入SDA         #define READ_SDA    GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_1)
    /* 初始化IIC  --------  --------  --------  --------  --------  --------  --------  --------  --------  --------  ----- */
    ---------函数名 IIC_Init
    ---------输入无
    ---------输出无
    ---------
    ---------
    /* 初始化IIC  --------  --------  --------  --------  --------  --------  --------  --------  --------  --------  ----- */  


    void IIC_Init(void)
    {                                             
            GPIO_InitTypeDef  GPIO_InitStructure;
            
            RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //输出
            GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
            GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//悬空
            GPIO_Init(GPIOB, &GPIO_InitStructure);

            IIC_SCL_1;//管脚置高
            IIC_SDA_1; //管脚置高
    }


    今天继续移植模拟的IIC也就是C51中的代码使用到STM32中。
    徐州工程学院(开发手册)STM32和zigbee技术文档杂记(1)中已经给出C51IIC的管脚的模拟代码
    首先我们开始改这个函数代码:
    /*******************************************************************
                         起动总线函数               
    函数原型: void  Start_I2c();  
    功能:     启动I2C总线,即发送I2C起始条件.  
    ********************************************************************/
    void Start_I2c()
    {
      SDA2=1;         /*发送起始条件的数据信号*/
      _Nop();
      SCK2=1;
      _Nop();        /*起始条件建立时间大于4.7us,延时*/
      _Nop();
      _Nop();
      _Nop();
      _Nop();   
      SDA2=0;         /*发送起始信号*/
      _Nop();        /* 起始条件锁定时间大于4μs*/
      _Nop();
      _Nop();
      _Nop();
      _Nop();      
      SCK2=0;       /*钳住I2C总线,准备发送或接收数据 */
      _Nop();
      _Nop();
    }
    这个事IIc的启动头信号代码。代码中有五个事件:SDA2=1; _Nop();SCK2=1; SDA2=0; SCK2=0;
    分析这五个代码
    SDA2=1;
    这一句很容就明白是SDA置高,并且是由STM32给芯片信号,也就是输出模式所以根据昨天的STM32F4的解析
    看上面的宏定义后就知道改成
    IIC_SDA_1;
    类似的SCK2=1; SDA2=0; SCK2=0;改成
    IIC_SCL_1; IIC_SDA_0 IIC_SCL_0;
    好了,那么就要解决_Nop();了
    由于这是移植,不是优化,所以我们完全将其代码原封不动的移植过来,所以时间上也调成一样的。
    在C51中代码时间约为1US。所以在STM32中设置1US的延迟
    ————————————止步
    这篇的核心就将怎么写具体的延时函数。
    下面有事一个较为麻烦的事儿。对于不准确的延时,只要空跑代码就行。看时钟就行,但是这里我将只用较为准确的延时。
    这里就涉及到STM32的
    在core_cm4.h文件中
    /** \brief  Structure type to access the System Timer (SysTick). */
    typedef struct
    {
      __IO uint32_t CTRL;                    /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */
      __IO uint32_t LOAD;                    /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register       */
      __IO uint32_t VAL;                     /*!< Offset: 0x008 (R/W)  SysTick Current Value Register      */
      __I  uint32_t CALIB;                   /*!< Offset: 0x00C (R/ )  SysTick Calibration Register        */
    } SysTick_Type;

    系统定时器,其中有四个参数:控制状态寄存器,重载寄存器,当前值寄存器,校准寄存器

    那么我们先用做的就是SYSCLK初始化①:系统时钟选用什么时钟源。
    在misc.h中有代码:
    /** @defgroup MISC_SysTick_clock_source
      * @{
      */


    #define SysTick_CLKSource_HCLK_Div8    ((uint32_t)0xFFFFFFFB)
    #define SysTick_CLKSource_HCLK         ((uint32_t)0x00000004)
    #define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SysTick_CLKSource_HCLK) || \
                                           ((SOURCE) == SysTick_CLKSource_HCLK_Div8))

    还有下方有这个函数
    void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);
    查看这个函数:
    /**
      * @brief  Configures the SysTick clock source.
      * @param  SysTick_CLKSource: specifies the SysTick clock source.
      *   This parameter can be one of the following values:
      *     @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source.
      *     @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source.
      * @retval None
      */
    void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
    {
      /* Check the parameters */
      assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));
      if (SysTick_CLKSource == SysTick_CLKSource_HCLK)
      {
        SysTick->CTRL |= SysTick_CLKSource_HCLK;
      }
      else
      {
        SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
      }
    }

    SysTick_CLKSource_HCLK_Div8: AHB时钟除以8选为SysTick时钟源。
    SysTick_CLKSource_HCLK:SysTick AHB时钟选为时钟源。
    那我们就在初始化函数中选用这个函数SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);        //选择外部时钟HCLK/8
    SYSTICK的时钟固定为HCLK时钟的1/8
    那么初始化函数大概可以这样写:
    void SysTick_Delay_init()
    {
         SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
    //选择外部时钟HCLK/8   SYSTICK的时钟固定为HCLK时钟的1/8
       
    }
    但是由于系统时钟是可以设置的,那么就设置一个输入参数,这样就不局限了。
    void SysTick_Delay_init(u8 Sys_clk)//Sys_clk单位是M。
    {
         SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
    //选择外部时钟HCLK/8   SYSTICK的时钟固定为HCLK时钟的1/8
       
    }
    Sys_clk输入参数也影响到us、ms的装载的值。所以还要设置一个中间静态变量static u8  MID_us=0;、
    static u16 MID_ms=0;//us、ms延时装载时要乘上的数
    那么改初始化程序为:
    void SysTick_Delay_init(u8 Sys_clk)//Sys_clk单位是M。
    {
         SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
    //选择外部时钟HCLK/8   SYSTICK的时钟固定为HCLK时钟的1/8
        MID_us=Sys_clk/8;        // 由于八分频所以除以8         MID_ms=(u16)MID_us*1000;//一毫秒等于1000微妙
    }
    那么对于ms:由于SysTick->LOAD为24位寄存器,所以,最大延时为:MAX_ms<=0xffffff*8*1000/(Sys_Ck*10^6)
    Sys_Ck单位为M,MAX_ms单位为ms
    //对72M条件下,MAX_ms<=1864.135

    那么写一个延时函数:这里原理就是51中设置预装定制值,开定时器,寻查到点的标志位,然后跳出循环,清除标志和装定制,就OK了。
    那么写出代码:
    计数器记一次就是8/(Sys_Ck*10^6)秒。对于72M那么Sys_Ck=72.
    那么现在就可以知道为什么要有
         MID_us=Sys_clk/8;        // 由于八分频所以除以8         MID_ms=(u16)MID_us*1000;//一毫秒等于1000微妙

    这两个数,这两个数乘上计数器一次的值就等于1.
    假设我要延时一毫秒,那么装载的数值为0.001/{8/(Sys_Ck*10^6)}=Sys_clk/8*1000== MID_ms;
    那么下面就是延时代码:
    void Delay_ms(u16 ms)
    {                                    
            u32 t;                  
            SysTick->LOAD=(u32)ms*MID_ms;//时间加载(SysTick->LOAD为24bit)
            SysTick->VAL =0x00;           //清空当前值计数器
            SysTick->CTRL=0x01 ;          //开始倒数  
            do
            {
                    t=SysTick->CTRL;
            }
            while(!(t&(1<<16))&&t&0x01);//判断时间是否到达   
            SysTick->CTRL=0x00;       //清除控制寄存器
            SysTick->VAL =0X00;       //清空当前值                     
    }   

    类似的US的代码:复制改一下MID_us,us。
    void Delay_us(u16 us)
    {                                    
            u32 t;                  
            SysTick->LOAD=(u32)us*MID_us;//时间加载(SysTick->LOAD为24bit)
            SysTick->VAL =0x00;           //清空当前值计数器
            SysTick->CTRL=0x01 ;          //开始倒数  
            do
            {
                    t=SysTick->CTRL;
            }
            while(!(t&(1<<16))&&t&0x01);//判断时间是否到达   
            SysTick->CTRL=0x00;       //清除控制寄存器
            SysTick->VAL =0X00;       //清空当前值                     
    }   

    那么在函数中建一个.h和.c包含以下就行了

    那么延时一毫秒只要Delay_us(1);
    分割线————————————————————
    对于那个_Nop();现在只要
    宏定义:
    #define    Delay_us(1)    _Nop()
    就行了。
    总结一下:这篇主要讲了配置系统定时器,实现准确延时。还更改了IIc的开始函数。
    今天就到这里。





    今天由于得到一个很不好的消息,我的大妈突然得病住院,而且情形很严重,很严重。
    ,可能这一段时间没心情也没时间写,所以更新会慢一点了。



    PCF8591与STM.jpg
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2016-12-8 15:01
  • 签到天数: 459 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2013-8-20 17:37:28 | 显示全部楼层
    沙发~楼主代码解析的挺好的啊~~~~
    祝家人身体健康
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2013-8-23 08:29
  • 签到天数: 20 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2013-8-23 08:30:41 | 显示全部楼层
    不错不错哒  
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2018-10-29 22:48
  • 签到天数: 731 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2014-1-16 12:48:56 | 显示全部楼层
    这块片子上没有硬件的IIC么?不过据说STM32的IIC确实是让很多人纠结的。
    代码解释得很详细,赞一个!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2014-4-21 09:44
  • 签到天数: 26 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2014-4-18 10:08:10 | 显示全部楼层
    看你的贴,很享受,很充实   谢谢楼主
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2013-7-2 13:29
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

     楼主| 发表于 2014-4-18 10:51:34 | 显示全部楼层
    shanghairen 发表于 2014-4-18 10:08
    看你的贴,很享受,很充实   谢谢楼主

    呵呵,谢谢啊
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2014-4-21 09:44
  • 签到天数: 26 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2014-4-21 09:42:52 | 显示全部楼层
    shen2008jie 发表于 2014-4-18 10:51
    呵呵,谢谢啊

    客气客气。多多好贴,让大家一起学习
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-5-7 19:21 , Processed in 0.182747 second(s), 28 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.