临近毕业,楼主发现自己感兴趣的东西越来越多。最近突然萌生学习STM32的念头。自知还有很多不足,所以要把自己的学习经历写下来与网友共享,一方面督促自己更多的深入学习,另一方面希望得到“众神”的引领、、、闲话少说。
程序:
/*
标题:STM32f103之USART+EXTI+TIMER+KEY+LED(简单综合应用)1
软件:Keil uVision4
硬件:stm32f103VCT6
author:蜡烛
data:2014-05-14
程序实现的功能描述:1.俩个LED灯以1S的频率交替闪烁
2.串口调试助手打开后显示结果信息
3.当有按键按下时,串口调试助手打印相关信息
(俩个按键中实现打印方式不一样: 一个按键是普通的判断IO口高地位;另一个通过外部中断实现)
特别说明:本程序是将一些单一的程序整合起来的 程序中加了很多注释,程序是可执行的
*/
#include "stm32f10x.h"
#include <stdio.h>
/* 以下是用到USART函数进行串口监视时需添加的代码 */
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
USART_SendData(USART1, (uint8_t) ch);
/* Loop until the end of transmission */
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
{}
return ch;
}
/* Private function prototypes
在这里楼主为了程序看起来更直观点,就把所涉及的函数都放在了这,没有采用多C文件,但在实际应用
编程中楼主建议采用多.C文件和对应的.h文件(或将所有接口函数都放在同一个.h文件)。或其他更好
的编程思想
*/
void Delay (uint32_t nCount);
void GPIO_Configuration(void);
void USART_Configuration(void);
void NVIC_Configuration(void);
void EXTI_Configuration(void);
void TIMER_Configuration(void);
/***********************************************************************/
int main(void)
{
GPIO_Configuration();//这里端口的配置为按键和LED小灯涉及到的IO口
USART_Configuration();//串口配置
NVIC_Configuration();//中断管理配置
EXTI_Configuration();//外部中断配置
TIMER_Configuration();//定时器配置
printf("***************************************************************\r\n");
printf("* *\r\n");
printf("* 最热情的问候 With My Warmest Regards ^_^ *\r\n");
printf("* *\r\n");
printf("***************************************************************\r\n");
/* Infinite loop */
while(1)
{
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2)!= RESET)
{
Delay (0xfffff);
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2)!= RESET)
{
printf("KeyB is Press\r\n");
while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2)!= RESET);
}
}
}
}
/***********************************************************************/
void Delay (uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
/***********************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC , ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启TIM2的时钟
/**
* LED1 -> PB0 LED2 -> PB1
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/*
KeyA -> PC13 , KeyB -> PB2
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
/***********************************************************************/
void USART_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,ENABLE);
/*
* USART1_TX -> PA9 , USART1_RX -> PA10
*/
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);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
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);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
USART_Cmd(USART1, ENABLE);
/* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
如下语句解决第1个字节无法正确发送出去的问题 */
USART_ClearFlag(USART1, USART_FLAG_TC); /* 清发送外城标志,Transmission Complete flag */
}
/***********************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/***********************************************************************/
void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource13);
EXTI_ClearITPendingBit(EXTI_Line13);
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_Line = EXTI_Line13;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
/*******************************************************************************
* Function Name : NVIC_Configuration
* Description : Configures the nested vectored interrupt controller.
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
void TIMER_Configuration() //定时器初始化程序
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_DeInit(TIM2); //重新将Timer设置为缺省值
TIM_InternalClockConfig(TIM2); //采用内部时钟给TIM2提供时钟源
TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1; //预分频系数为36000-1,这样计数器时钟为72MHz/36000 = 2kHz
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割 0
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置计数器模式为向上计数模式
TIM_TimeBaseStructure.TIM_Period = 2000 - 1; //设置计数溢出大小,每计2000个数就产生一个更新事件;这里定时1s
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure); //将配置应用到TIM2中
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除溢出中断标志
TIM_ARRPreloadConfig(TIM2, DISABLE); //禁止ARR预装载缓冲器
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //开启TIM2的中断
TIM_Cmd(TIM2,ENABLE); //开启定时器2
}
/*******************************************************************************
* Function Name : EXTI15_10_IRQHandler
* Description : This function handles External lines 10-15 interrupt request.
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
void EXTI15_10_IRQHandler(void)//中断处理函数的函数名都是默认好的,如果您修改了此处的函数名,会使得此函数无效
{
if ( EXTI_GetITStatus(EXTI_Line13) != RESET ) {
EXTI_ClearITPendingBit(EXTI_Line13);//发生中断后,需清楚中断标志位,此处如果不清除,会使得串口一直在打印"KeyA is Press\r\n"
printf("KeyA is Press\r\n");
}
}
void TIM2_IRQHandler(void)
{
static u8 ReadValue;
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //判断是否发生中断溢出更新事件
{
TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);
//清除TIM2的中断标志位 如果没清除将导致俩个灯看起来都亮,按下KEYA键打印消息,按下KEYB键则不打印消息,这
//是因为KEYA键采用的外部中断的优先级别高于TIM2的优先级,所以不按按键时,程序一直在TIM2的中断处理函数里面循环
//这才导致按下KEYB键后没有响应和俩个LED灯一直亮着
ReadValue = GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0);
if(ReadValue == 1)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_0);
GPIO_SetBits(GPIOB, GPIO_Pin_1);
}
else
{
GPIO_ResetBits(GPIOB, GPIO_Pin_1);
GPIO_SetBits(GPIOB, GPIO_Pin_0);
}
}
}
结果: