目录
1、IO的几种模式
2、 GPIO初始化(led)
3、 GPIO初始化(key)
4、主函数初始化
5、硬件延时函数
6、中断EXTI及NVIC配置
7、通用定时器
8、USART的使用
工程文件夹示意图:
软件中建立文件夹所包含内容:
魔术棒配置:
1、IO的几种模式:
/* 选择IO接口工作方式: GPIO_Mode_AIN 模拟输入 GPIO_Mode_IN_FLOATING 浮空输入 GPIO_Mode_IPD 下拉输入 用于按键,具体看电路图 GPIO_Mode_IPU 上拉输入 用于按键,具体看电路图 GPIO_Mode_Out_PP 推挽输出 用于LED GPIO_Mode_Out_OD 开漏输出 GPIO_Mode_AF_PP 复用推挽输出 GPIO_Mode_AF_OD 复用开漏输出 */
2、 GPIO初始化(led)
需要建立led.c及led.h文件
Led.c内容:
#include "led.h" //LED灯的接口初始化,"void LED_Config(void);"需要在led.h中进行声明 void LED_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //开启总线时钟 GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9; //选择端口号(0~15或all) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择IO接口工作方式,使用推挽输出模式,可输出高低电平 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz) GPIO_Init(GPIOC, &GPIO_InitStructure); }
Led.h内容:
#ifndef __LED_H #define __LED_H #include "stm32f10x.h"//包含库头文件,才可使用库函数,如 GPIO_SetBits(GPIOC, GPIO_Pin_6); void LED_Config(void);//进行函数名的声明 #endif
3、 GPIO初始化(key)
需要建立key.c及key.h文件
key.c内容:
#include "key.h" //KEY的接口初始化 void KEY_Config(void){ GPIO_InitTypeDef GPIO_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //开启总线时钟 GPIO_InitStruct.GPIO_Pin =GPIO_Pin_8|GPIO_Pin_9; //选择端口号(0~15或all) GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式,上拉模式 // GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //按键为输入,不用设置IO接口速度 GPIO_Init(GPIOB, &GPIO_InitStruct); }
key.h内容:
#ifndef __KEY_H #define __KEY_H #include "stm32f10x.h" void KEY_Config(void);//进行函数名的声明 #endif
4、主函数初始化:
#include "stm32f10x.h" #include "led.h" //包含头文件 #include "key.h"//包含头文件 int main(void){ uint32_t t=2;//定义变量必须在初始化前面 KEY_Config();//在此处进行初始化 LED_Config();//在此处进行初始化 while(1){ } }
5、硬件延时函数:
delay.c内容:
#include "delay.h" void delay_us ( unsigned int us) //微秒级延时函数,嘀嗒定时器为24位向下计数器 { SysTick -> VAL = 0; //设置计数器初值为0,一共32位,24位可用 SysTick -> LOAD = 9*us; //每计9个数才是1us,这里和TIM定时器计数有区别 SysTick -> CTRL = 0x01; //使能计数器,第0位为使能位,置1使能,置0失能 while((SysTick ->CTRL) != 0x10001); //向下产生溢出后,产生中断标志,及判断16位是否置1 SysTick -> CTRL =0; //产生溢出后,产生中断标志的第16位被置1,此时再将第16位置0,以便下次计数 SysTick -> VAL =0; //设置计数器初值为0,一共32位,24位可用 } void delay_ms ( unsigned int ms) //毫秒级延时函数,嘀嗒定时器为24位向下计数器 { SysTick -> VAL = 0;//设置计数器初值为0,一共32位,24位可用 SysTick -> LOAD = 9000*ms;//这里计9000个数才是1ms,这里和TIM定时器计数有区别 SysTick -> CTRL = 0x01;//使能计数器,第0位为使能位,置1使能,置0失能 while((SysTick ->CTRL) != 0x10001);//向下产生溢出后,产生中断标志,及判断16位是否置1 SysTick -> CTRL =0;//产生溢出后,产生中断标志的第16位被置1,此时再将第16位置0,以便下次计数 SysTick -> VAL =0;//设置计数器初值为0,一共32位,24位可用 }
delay.h内容:
#ifndef __DELAY_H #define __DELAY_H #include "stm32f10x.h" void delay_us(unsigned int us); void delay_ms(unsigned int ms); #endif
不用在main.c中初始化,只需要包含#include "delay.h"即可,就可以进行函数的调用:delay_ms(100);
6、中断EXTI及NVIC配置:
exti.c内容:
#include "exti.h" //EXTI的接口初始化及NVIC配置 void EXTI_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; //GPIO端口的初始化 EXTI_InitTypeDef EXTI_InitStructure; //EXTI配置 NVIC_InitTypeDef NVIC_InitStruct; //NVIC配置 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//第一组 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //开启GPIO端口时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //开启GPIO端口复用时钟 GPIO_InitStructure.GPIO_Pin =GPIO_Pin_8|GPIO_Pin_9; //选择端口号(0~15或all) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 ,上拉模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz) GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource8); //将中断线与引脚连接起来,GPIO_PortSourceGPIOB固件库手册有错 GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource9); //将中断线与引脚连接起来,GPIO_PortSourceGPIOB固件库手册有错 EXTI_InitStructure.EXTI_Line = EXTI_Line8|EXTI_Line9; //对应中断IO口的引脚,Pin_8,Pin_9 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断触发模式 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发方式 EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;//第5~9线通用 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;//主优先级 NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;//从优先级 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); }
exti.h内容:
#ifndef __EXTI_H #define __EXTI_H #include "stm32f10x.h" #include "exti.h" void EXTI_Config(void); #endif
主函数main.c中需要包含头文件:#include "exti.h" 并进行初始化:EXTI_Config();
中断函数文件 "stm32f10x_it.c" 需要包含led.h key.h delay.h exti.h 才能实现相应的功能
stm32f10x_it.c 需要添加的内容:
#include "exti.h" #include "beep.h" #include "delay.h" #include "led.h" //按键产生中断,进入此函数进行以下两个if语句判断 void EXTI9_5_IRQHandler (void)//固定函数名,不可自定义,否则无法进入中断 { if((EXTI_GetITStatus(EXTI_Line8) == 1)|(EXTI_GetITStatus(EXTI_Line9) == 1)){ if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_8)==0){ delay_ms(20); BEEP_Warning();//蜂鸣器鸣叫功能 } if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9)==0){ delay_ms(20); LM_Led(); //流水灯功能 } } EXTI_ClearITPendingBit(EXTI_Line8);//必须进行中断挂起位的清除,否则无法进入下次中断 EXTI_ClearITPendingBit(EXTI_Line9); }
7、通用定时器
timer.c包含内容:
#include "timer.h" static void TIMER3_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断组为0 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn ; // 设置中断来源 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 设置主优先级为 0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 设置抢占优先级为3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } static void TIMER3_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);// 开启定时器时钟,即内部时钟CK_INT=72M TIM_TimeBaseStructure.TIM_Period = 1000-1; // 计数的次数 ARR ;如果计1000次数,那么写成1000-1,后面计算的时候会自动加1 //即1000次(1000us)溢出,产生中断,此时在中断函数中定义一个变量记录中断次数 TIM_TimeBaseStructure.TIM_Prescaler= 72-1;// 分频因子 PSC ;如果分72,那么写成72-1,后面计算的时候会自动加1 // 时钟分频因子 ,基本定时器没有,不用管 // TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重复计数器的值,基本定时器没有,不用管 // TIM_TimeBaseStructure.TIM_RepetitionCounter=0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);// 初始化定时器 TIM_ClearFlag(TIM3, TIM_FLAG_Update);// 清除计数器中断标志位 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);// 开启计数器中断 TIM_Cmd(TIM3, ENABLE);// 使能计数器 } void TIMER3_Init(void){ TIMER3_NVIC_Config(); TIMER3_Config(); }
timer.h 包含内容:
#ifndef __TIMER_H #define __TIMER_H #include "stm32f10x.h" void TIMER3_Init(void); #endif
主函数main.c中进行初始化:TIMER3_Init();初始化后计数器将开始自动计时,不需要外部干预,计数完后将自动跳到 "stm32f10x_it.c" 中,执行完中断函数后,自动返回主函数上次断点继续执行
执行相关的中断程序:
//执行流水灯功能 void TIM3_IRQHandler(void) //固定函数名称 { if ( TIM_GetITStatus( TIM3, TIM_IT_Update) != RESET ) //检查指定的 TIM 中断发生与否 { Countcycle++;//记录中断次数,uint16_t Countcycle就在stm32f10x_it.c开头进行定义 switch(Countcycle){ case 1000 : GPIO_SetBits(GPIOC, GPIO_Pin_6); GPIO_ResetBits(GPIOC, GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9); break; case 2000 : GPIO_SetBits(GPIOC, GPIO_Pin_7); GPIO_ResetBits(GPIOC, GPIO_Pin_6|GPIO_Pin_8|GPIO_Pin_9); break; case 3000 : GPIO_SetBits(GPIOC, GPIO_Pin_8); GPIO_ResetBits(GPIOC, GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_9); break; case 4000 : GPIO_SetBits(GPIOC, GPIO_Pin_9); GPIO_ResetBits(GPIOC, GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8); Countcycle=0;break; } TIM_ClearITPendingBit(TIM3 , TIM_FLAG_Update); //清除 TIMx 的中断待处理位 } }
8、USART的使用:
usart.c内容:
#include "usart.h" static void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//嵌套向量中断控制器组选择 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;// 配置USART为中断源 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;// 抢断优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断 NVIC_Init(&NVIC_InitStructure);// 初始化配置NVIC } void USART_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 打开串口GPIO的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);// 打开串口外设的时钟 // 将USART Tx的GPIO配置为推挽复用模式 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//推挽复用 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 将USART Rx的GPIO配置为浮空输入模式 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置串口的工作参数 USART_InitStructure.USART_BaudRate = 115200;// 配置波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b;// 配置 针数据字长 USART_InitStructure.USART_StopBits = USART_StopBits_1;// 配置停止位 USART_InitStructure.USART_Parity = USART_Parity_No ;// 配置校验位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 配置硬件流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;// 配置工作模式,收发一起 USART_Init(USART1, &USART_InitStructure);// 完成串口的初始化配置 NVIC_Configuration();// 串口中断优先级配置,上面已经配置,直接调用 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 使能串口接收中断 USART_Cmd(USART1, ENABLE);// 使能串口 } //重定向c库函数printf到串口,重定向后可使用printf函数,使用该函数是,需要在魔术棒中的Target选项卡中勾选使用微库或包含头文件#include "stdio.h" int fputc(int ch, FILE *f)//用法:printf( "这是一个串口打印实验\n" ); { USART_SendData(USART1, (uint8_t) ch);//发送一个字节数据到串口 while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送完毕 return (ch); }
usart.h内容:
#ifndef __BSP_USART_H #define __BSP_USART_H #include "stm32f10x.h" #include <stdio.h> //在此处包含即可 void USART_Config(void); #endif
"stm32f10x_it.c"中需要包含头文件 #include "usart.h" 和中断服务函数:
//串口中断服务函数 void USART1_IRQHandler(void)//固定函数名 { uint8_t ucTemp; if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) { ucTemp = USART_ReceiveData(USART1);//接受到数据存放至变量ucTemp中 USART_SendData(USART1,ucTemp); //变量ucTemp中数据发出去 } }
主函数main.c中进行初始化:USART_Config(); 并包含头文件 #include "usart.h"
主函数main.c内容:
#include "stm32f10x.h" #include "usart.h" #include "delay.h" int main(void) { USART_Config(); while (1) { delay_ms(1000); printf( "lin辰傍边的风\n" ); } }