徐州工程学院(开发手册)STM32之驱动移植杂记(2)
#竞赛
4311 人阅读
|
6 人回复
|
2013-08-20
TA的每日心情 | 开心 2013-7-2 13:29 |
|---|
签到天数: 1 天 连续签到: 1 天 [LV.1]初来乍到
举人
- 积分
- 706

|
本帖最后由 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的开始函数。
今天就到这里。
今天由于得到一个很不好的消息,我的大妈突然得病住院,而且情形很严重,很严重。
,可能这一段时间没心情也没时间写,所以更新会慢一点了。
|
|
|
|
|
|
|
|
|
TA的每日心情 | 开心 2016-12-8 15:01 |
|---|
签到天数: 459 天 连续签到: 1 天 [LV.9]以坛为家II
进士
- 积分
- 2641

|
沙发
zhaojunlin-1847508
发表于 2013-8-20 17:37:28
|
只看该作者
沙发~楼主代码解析的挺好的啊~~~~
祝家人身体健康 |
|
|
|
|
|
|
|
|
TA的每日心情 | 开心 2013-8-23 08:29 |
|---|
签到天数: 20 天 连续签到: 1 天 [LV.4]偶尔看看III
秀才
- 积分
- 202

|
板凳
richardglx
发表于 2013-8-23 08:30:41
|
只看该作者
|
|
|
|
|
|
|
|
TA的每日心情 | 奋斗 2018-10-29 22:48 |
|---|
签到天数: 731 天 连续签到: 1 天 [LV.9]以坛为家II
状元
- 积分
- 6289
  

|
地板
suyong_yq
发表于 2014-1-16 12:48:56
|
只看该作者
这块片子上没有硬件的IIC么?不过据说STM32的IIC确实是让很多人纠结的。
代码解释得很详细,赞一个! |
|
|
|
|
|
|
|
|
TA的每日心情 | 开心 2014-4-21 09:44 |
|---|
签到天数: 26 天 连续签到: 1 天 [LV.4]偶尔看看III
进士
- 积分
- 2740
|
5#
shanghairen
发表于 2014-4-18 10:08:10
|
只看该作者
看你的贴,很享受,很充实 谢谢楼主  |
|
|
|
|
|
|
|
|
TA的每日心情 | 开心 2013-7-2 13:29 |
|---|
签到天数: 1 天 连续签到: 1 天 [LV.1]初来乍到
举人
- 积分
- 706

|
6#
ssj-413971
发表于 2014-4-18 10:51:34
|
只看该作者
shanghairen 发表于 2014-4-18 10:08 ![]()
看你的贴,很享受,很充实 谢谢楼主
呵呵,谢谢啊 |
|
|
|
|
|
|
|
|
TA的每日心情 | 开心 2014-4-21 09:44 |
|---|
签到天数: 26 天 连续签到: 1 天 [LV.4]偶尔看看III
进士
- 积分
- 2740
|
7#
shanghairen
发表于 2014-4-21 09:42:52
|
只看该作者
shen2008jie 发表于 2014-4-18 10:51 ![]()
呵呵,谢谢啊
客气客气。多多好贴,让大家一起学习 |
|
|
|
|
|
|
|
|