STM32F103C8T6学习笔记

一:芯片简介

二:外设使用

1:GPIO初始化

使用以下代码对GPIO进行初始化:

void GPIO_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx,ENABLE);//开启APB2总线上GPIOx端口的时钟GPIO_InitTypeDef GPIO_InitStructure;    //定义GPIO初始化结构体GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//给GPIO结构体中成员:”GPIO_Mode” 赋值//GPIO_Mode_AIN = 模拟输入;//GPIO_Mode_IN_FLOATING = 浮空输入;//GPIO_Mode_IPD = 下拉输入;//GPIO_Mode_IPU = 上拉输入;//GPIO_Mode_Out_OD = 开漏输出;//GPIO_Mode_Out_PP = 推挽输出;//GPIO_Mode_AF_OD = 复用开漏输出,//GPIO_Mode_AF_PP = 复用推挽输出;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;//给GPIO结构体中成员:”GPIO_Pin” 赋值,GPIO_Pin_0 - GPIO_Pin_15 - GPIO_Pin_AllGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//给GPIO结构体中成员:”GPIO_Speed” 赋值,GPIO的反转速度 //GPIO_Speed_10MHz//GPIO_Speed_2MHz//GPIO_Speed_50MHzGPIO_Init(GPIOx, &GPIO_InitStructure);//调用初始化好的GPIO结构体	
}

这样我们就配置好需要的GPIO,然后使用输入或输出的函数控制GPIO口

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//读取输入io口的电平并返回 高电平返回1,低电平返回0;uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
//读取整个输入端口的数据 
//返回输入数据寄存器的16位数据(高16位保留),用来读取输入模式下一组IO口电平状态uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//读取输出端口的电平 高电平返回1,低电平返回0;uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
//读取整个输出端口的数据 
//返回输出数据寄存器的16位数据(高16位保留),用来读取输出模式下一组IO口电平状态void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//拉高引脚输出电平void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//拉低引脚输出电平void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
//通过向置位/复位寄存器高16位或低16位置1实现某个IO输出高低电平
//注意:如果同时将置位/复位寄存器高16位及低16位都置1,则低16位优先级更高void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
//直接向输出数据寄存器低16位写入16位数据,达到控制一组IO电平的目的
//注意:如果同时将置位/复位寄存器高16位及低16位都置1,则低16位优先级更高

点亮LED灯实例

//灯的打开
void LED1_ON(void)
{GPIO_ResetBits(GPIOB, GPIO_Pin_1);
}
//灯的熄灭
void LED1_OFF(void)
{GPIO_SetBits(GPIOB, GPIO_Pin_1);
}
//灯的翻转方法一
void LED1_Turn(void)
{if (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_1) == 0){GPIO_SetBits(GPIOB, GPIO_Pin_1);}else{GPIO_ResetBits(GPIOB, GPIO_Pin_1);}
}
//灯的翻转方法2
void LED1_Turn_2(void)
{GPIO_WriteBit(GPIOB,GPIO_Pin_1,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_1)));
}

 

补充知识点: 

开漏输出 = 高电平高阻态,无驱动能力常用于I2C通信,总线接上拉电阻。
推挽输出 = 高低电平都有驱动能力;

初始化的第一步开启时钟,这里总共涉及了RCC和GPIO两个外设

★常用的三个RCC外设

void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
//This parameter can be any combination of the following values:
//RCC_AHBPeriph_OTG_FS 
//RCC_AHBPeriph_ETH_MACvoid RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
//RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB,
//RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,
//RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,
//RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,
//RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,
//RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,
//RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11.  void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
//RCC_APB1Periph_TIM2, RCC_APB1Periph_TIM3, RCC_APB1Periph_TIM4,
//RCC_APB1Periph_TIM5, RCC_APB1Periph_TIM6, RCC_APB1Periph_TIM7,
//RCC_APB1Periph_WWDG, RCC_APB1Periph_SPI2, RCC_APB1Periph_SPI3,
//RCC_APB1Periph_USART2, RCC_APB1Periph_USART3, RCC_APB1Periph_USART4, 
//RCC_APB1Periph_USART5, RCC_APB1Periph_I2C1, RCC_APB1Periph_I2C2,
//RCC_APB1Periph_USB, RCC_APB1Periph_CAN1, RCC_APB1Periph_BKP,
//RCC_APB1Periph_PWR, RCC_APB1Periph_DAC, RCC_APB1Periph_CEC,
//RCC_APB1Periph_TIM12, RCC_APB1Periph_TIM13, RCC_APB1Periph_TIM14  

2:延时函数

使用以下代码进行相应的延时:

方法一:操作寄存器模式
注意如果在延时的时候,进入中断且中断中又进入该延时函数会造成死循环,需要修改函数

#include "stm32f10x.h"/*** @brief  微秒级延时* @param  xus 延时时长,范围:0~233015* @retval 无*/
void Delay_us(uint32_t xus)
{	SysTick->LOAD = 72 * xus;				//设置定时器重装值SysTick->VAL = 0x00;					//清空当前计数值SysTick->CTRL = 0x00000005;				//设置时钟源为HCLK,启动定时器while(!(SysTick->CTRL & 0x00010000));   //等待计数到0 当计数器的值减小到0的时候,CRTL寄存器的位16会置1SysTick->CTRL = 0x00000004;				//关闭定时器
}
/*** @brief  毫秒级延时* @param  xms 延时时长,范围:0~4294967295* @retval 无*/
void Delay_ms(uint32_t xms)
{while(xms--){Delay_us(1000);}
}/*** @brief  秒级延时* @param  xs 延时时长,范围:0~4294967295* @retval 无*/
void Delay_s(uint32_t xs)
{while(xs--){Delay_ms(1000);}
} 

方法二:中断延时法
注意由于中断的优先级的原因,不能再中断中使用中断延时函数,因为系统默认该延时中断的优先及为最低,所以在高中断优先级的中断中,延时函数的中断无法触发,可以通过修改延时中断优先级调整。

//以下程序是根据官方程序修改的
#include "systick.h"u32 TimingDelay;void Delay_us(__IO uint32_t nTime)
{ if (SysTick_Config(SystemCoreClock / 1000000)){ /* Capture error */ exit(1);}TimingDelay = nTime;while(TimingDelay != 0);SysTick->CTRL = 0x00;SysTick->VAL = 0x00;
}void Delay_ms(__IO uint32_t nTime)
{ if (SysTick_Config(SystemCoreClock / 1000)){ /* Capture error */ exit(1);}TimingDelay = nTime;while(TimingDelay != 0);SysTick->CTRL = 0x00;   //失能SysTickSysTick->VAL = 0x00;    //当前值清零 
}void Delay_s(__IO uint32_t nTime)
{ if (SysTick_Config(SystemCoreClock / 1)){ /* Capture error */ exit(1);}TimingDelay = nTime;while(TimingDelay != 0);SysTick->CTRL = 0x00;SysTick->VAL = 0x00;
}void SysTick_Handler(void)
{if (TimingDelay != 0){ TimingDelay--;}
}

补充知识点

SysTick寄存器

因为系统滴答定时器属于Cotex-M3内核的外设,相关寄存器介绍不在《参考手册》,而在《3_STM32F10xx Cortex-M3编程手册》,后简称《编程手册》
SYSTICK 的时钟固定为HCLK 时钟,在这里我们选用内部时钟源72M,所以SYSTICK的时钟为72M,即SYSTICK定时器以72M的频率递减。

 可以通过控制SysTick寄存器控制系统定时器,SysTick寄存器块的基址是OxE000 E010
0x00 STK_CTRL
0x04 STK_LOAD
0x08 STK_VAL
0x0C STK_CALIB
系统滴答定时器控制和状态寄存器(STK_CTRL)

系统滴答定时器加载值寄存器(STK_LOAD)
在这里插入图片描述
Bit[23:0],一共24位,用来设置系统滴答定时器的初始值,因此范围为1~ 16777216。

系统滴答定时器当前值寄存器(STK_VAL)
在这里插入图片描述
在这里插入图片描述
Bit[23:0],一共24位,用来获取当前系统滴答定时器的计数值。

SysTick_Config(SystemCoreClock)函数

//函数原型
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)  return (1);      /* Reload value impossible */SysTick->LOAD  = ticks - 1;                                  /* set reload register */NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |SysTick_CTRL_TICKINT_Msk   |SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */return (0);                                                  /* Function successful */
}

1、该函数的功能:

①设置Systick定时器重装载值,该函数的参数就代表了重装载值。
②设置Systick定时中断优先级
③启动Systick定时器运行

2、该函数的形参表示内核时钟多少个周期后触发一次Systick定时中断。而SystemCoreClock是固件中定义的系统内核时钟,因此SysTick_Config(SystemCoreClock)就表示每1s钟触发一次Systick定时中断,进而SysTick_Config(SystemCoreClock/10)就表示没100ms触发一次Systick定时中断,于是要想每1ms触发一次Systick定时中断就应该配置为SysTick_Config(SystemCoreClock/1000)。

3、如果采用寄存器级编程,直接对Systick这个定时器进行配置,那么每次就要操作好几个寄存器(包括LOAD、VAL和CTRL),但是ST公司通过标准库的形式将“对Systick的访问”封装成SysTick_Config这个函数了,程序员只需要配置好该函数的参数就可以一键实现特定的定时中断了。

4、SysTick定时器是一个24bit的定时器,所以可装载的值最多为16777215,对于SysTick_Config函数来说,如果参数值超过16777215,即16.7M,那么就会返回1,参数值小于该值,则返回0。利用这个返回值就可以判定SysTick定时器有没有配置成功。

5、SysTick定时器是靠系统内核时钟来驱动的,所以如果系统内核时钟停止了,那么SysTick定时器也就停止计数了,所以当系统挂起或者调试过程中,由于系统内核时钟停止了,所以SysTick定时器也就停止计数了。

3:EXTI外部中断

使用以下代码配置EXTI外部中断:

#include "stm32f10x.h"                  // Device headeruint16_t CountSensor_Count;void CountSensor_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE);//开启APB2总线上GPIOx端口的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//开启APB2总线上GPIOx端口的时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line14;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_Init(&EXTI_InitStructure);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);
}uint16_t CountSensor_Get(void)
{return CountSensor_Count;
}void EXTI15_10_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line14) == SET){/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0){CountSensor_Count ++;}EXTI_ClearITPendingBit(EXTI_Line14);}
}

NVIC


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部