STM32F103RCT6 学习笔记2

代码修改与调用模块:

1.GPIO输入通用—LED

/*********************************************************************************************************
*                                              内部函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:ConfigLEDGPIO
* 函数功能:配置LED的GPIO 
* 输入参数:void 
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
static  void  ConfigLEDGPIO(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;  //GPIO_InitStructure用于存放GPIO的参数
                                                                     
  //使能RCC相关时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //使能GPIOC的时钟
                                                                                                                 
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4;           //设置引脚
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //设置I/O输出速度
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;     //设置模式
  GPIO_Init(GPIOC, &GPIO_InitStructure);                //根据参数初始化LED1的GPIO

  GPIO_WriteBit(GPIOC, GPIO_Pin_4, Bit_SET);            //将LED1默认状态设置为点亮

  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_5;           //设置引脚
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     //设置I/O输出速度
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;     //设置模式
  GPIO_Init(GPIOC, &GPIO_InitStructure);                //根据参数初始化LED2的GPIO

  GPIO_WriteBit(GPIOC, GPIO_Pin_5, Bit_RESET);          //将LED2默认状态设置为熄灭
}

/*********************************************************************************************************
*                                              API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:InitLED
* 函数功能:初始化LED模块
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
void InitLED(void)
{
  ConfigLEDGPIO();  //配置LED的GPIO
}

/*********************************************************************************************************
* 函数名称:LEDFlicker
* 函数功能:LED闪烁函数
* 输入参数:cnt
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:LEDFlicker在Proc2msTask中调用,cnt为250时表示每500ms更改一次LED状态
*********************************************************************************************************/
void LEDFlicker(u16 cnt)
{
  static u16 s_iCnt;  //定义静态变量s_iCnt作为计数器
  
  s_iCnt++; //计数器的计数值加1
  
  if(s_iCnt >= cnt)   //计数器的计数值大于cnt
  { 
    s_iCnt = 0;       //重置计数器的计数值为0

    //LED1状态取反,实现LED0闪烁
    GPIO_WriteBit(GPIOC, GPIO_Pin_4, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_4)));
    
    //LED2状态取反,实现LED1闪烁
    GPIO_WriteBit(GPIOC, GPIO_Pin_5, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_5)));
  }
}

2.GPIO与按键:

/*********************************************************************************************************
* 函数名称:ConfigKeyOneGPIO
* 函数功能:配置按键的GPIO 
* 输入参数:void 
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
static  void  ConfigKeyOneGPIO(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;  //GPIO_InitStructure用于存放GPIO的参数
  
  //使能RCC相关时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //使能GPIOC的时钟
  
  //配置PC1
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_1;           //设置引脚
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;        //设置输入类型
  GPIO_Init(GPIOC, &GPIO_InitStructure);                //根据参数初始化GPIO
  
  //配置PC2
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2;           //设置引脚
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;        //设置输入类型
  GPIO_Init(GPIOC, &GPIO_InitStructure);                //根据参数初始化GPIO

  //配置PA0
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0;           //设置引脚
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;        //设置输入类型
  GPIO_Init(GPIOA, &GPIO_InitStructure);                //根据参数初始化GPIO
}

/*********************************************************************************************************
*                                              API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:InitKeyOne
* 函数功能:初始化KeyOne模块
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
void InitKeyOne(void)
{
  ConfigKeyOneGPIO(); //配置按键的GPIO 
                                                                
  s_arrKeyDownLevel[KEY_NAME_KEY1] = KEY_DOWN_LEVEL_KEY1;  //按键KEY1按下时为低电平
  s_arrKeyDownLevel[KEY_NAME_KEY2] = KEY_DOWN_LEVEL_KEY2;  //按键KEY2按下时为低电平
  s_arrKeyDownLevel[KEY_NAME_KEY3] = KEY_DOWN_LEVEL_KEY3;  //按键KEY3按下时为低电平
}

/*********************************************************************************************************
* 函数名称:ScanKeyOne
* 函数功能:按键扫描,每10ms调用一次
* 输入参数:keyName-按键名,OnKeyOneUp-按键弹起响应函数的指针,OnKeyOneDown-按键按下响应函数的指针
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:如果s_arrKeyDownLevel[keyName] = 0xFF,对s_arrKeyDownLevel[keyName]直接取反得出的是256,而非0
*           正确的做法是(u8)(~s_arrKeyDownLevel[keyName]),这样得出的才是0。
*********************************************************************************************************/
void ScanKeyOne(u8 keyName, void(*OnKeyOneUp)(void), void(*OnKeyOneDown)(void))
{
  static  u8  s_arrKeyVal[KEY_NAME_MAX];    //定义一个u8类型的数组,用于存放按键的数值
  static  u8  s_arrKeyFlag[KEY_NAME_MAX];   //定义一个u8类型的数组,用于存放按键的标志位
  
  s_arrKeyVal[keyName] = s_arrKeyVal[keyName] << 1;   //左移一位

  switch (keyName)
  {
    case KEY_NAME_KEY1:
      s_arrKeyVal[keyName] = s_arrKeyVal[keyName] | KEY1; //按下/弹起时,KEY1为0/1
      break;                                            
    case KEY_NAME_KEY2:                                 
      s_arrKeyVal[keyName] = s_arrKeyVal[keyName] | KEY2; //按下/弹起时,KEY2为0/1
      break;                                            
    case KEY_NAME_KEY3:                                 
      s_arrKeyVal[keyName] = s_arrKeyVal[keyName] | KEY3; //按下/弹起时,KEY3为0/1
      break;                                            
    default:
      break;
  }  
  
  //按键标志位的值为TRUE时,判断是否有按键有效按下
  if(s_arrKeyVal[keyName] == s_arrKeyDownLevel[keyName] && s_arrKeyFlag[keyName] == TRUE)
  {
    (*OnKeyOneDown)();                    //执行按键按下的响应函数
    s_arrKeyFlag[keyName] = FALSE;        //表示按键处于按下状态,按键标志位的值更改为FALSE
  }
  
  //按键标志位的值为FALSE时,判断是否有按键有效弹起
  else if(s_arrKeyVal[keyName] == (u8)(~s_arrKeyDownLevel[keyName]) && s_arrKeyFlag[keyName] == FALSE)
  {
    (*OnKeyOneUp)();                      //执行按键弹起的响应函数
    s_arrKeyFlag[keyName] = TRUE;         //表示按键处于弹起状态,按键标志位的值更改为TRUE
  }
}

3.串口通信

简单双向串口通信有两根通信线(发送端TX和接收端RX)

TX与RX要交叉连接 当只需单向的数据传输时,可以只接一根通信线

当电平标准不一致时,需要加电平转换芯片

TTL电平:+3.3V或+5V表示1,0V表示0

RS232电平:-3~-15V表示1,+3~+15V表示0

RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)

波特率:串口通信的速率

起始位:标志一个数据帧的开始,固定为低电平

数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行

校验位:用于数据验证,根据数据位计算得来

停止位:用于数据帧间隔,固定为高电平

USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器 USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里 自带波特率发生器,最高达4.5Mbits/s 可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2) 可选校验位(无校验/奇校验/偶校验) 支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN

STM32F103C8T6 USART资源: USART1、 USART2、 USART3

发送器和接收器的波特率由波特率寄存器BRR里的DIV确定

计算公式:波特率 = fPCLK2/1 / (16 * DIV)

*                                              内部函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:InitUARTBuf
* 函数功能:初始化串口缓冲区,包括发送缓冲区和接收缓冲区  
* 输入参数:void
* 输出参数:void
* 返 回 值:void 
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
static  void  InitUARTBuf(void)
{
  i16 i;

  for(i = 0; i < UART1_BUF_SIZE; i++)
  {
    s_arrSendBuf[i] = 0;
    s_arrRecBuf[i]  = 0;  
  }

  InitQueue(&s_structUARTSendCirQue, s_arrSendBuf, UART1_BUF_SIZE);
  InitQueue(&s_structUARTRecCirQue,  s_arrRecBuf,  UART1_BUF_SIZE);
}

/*********************************************************************************************************
* 函数名称:WriteReceiveBuf
* 函数功能:写数据到串口接收缓冲区 
* 输入参数:d,待写入串口接收缓冲区的数据
* 输出参数:void
* 返 回 值:写入数据成功标志,0-不成功,1-成功 
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
static  u8  WriteReceiveBuf(u8 d)
{
  u8 ok = 0;  //写入数据成功标志,0-不成功,1-成功
                                                                    
  ok = EnQueue(&s_structUARTRecCirQue, &d, 1);   
                                                                    
  return ok;  //返回写入数据成功标志,0-不成功,1-成功 
}

/*********************************************************************************************************
* 函数名称:ReadSendBuf
* 函数功能:读取串口发送缓冲区中的数据 
* 输入参数:p,读出来的数据存放的首地址
* 输出参数:p,读出来的数据存放的首地址
* 返 回 值:读取数据成功标志,0-不成功,1-成功 
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
static  u8  ReadSendBuf(u8 *p)
{
  u8 ok = 0;  //读取数据成功标志,0-不成功,1-成功
                                                                   
  ok = DeQueue(&s_structUARTSendCirQue, p, 1);  
                                                                   
  return ok;  //返回读取数据成功标志,0-不成功,1-成功 
}

/*********************************************************************************************************
* 函数名称:ConfigUART
* 函数功能:配置串口相关的参数,包括GPIO、RCC、USART和NVIC  
* 输入参数:bound,波特率
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
static  void  ConfigUART(u32 bound)
{
  GPIO_InitTypeDef  GPIO_InitStructure;   //GPIO_InitStructure用于存放GPIO的参数
  USART_InitTypeDef USART_InitStructure;  //USART_InitStructure用于存放USART的参数
  NVIC_InitTypeDef  NVIC_InitStructure;   //NVIC_InitStructure用于存放NVIC的参数
  
  //使能RCC相关时钟                                                            
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);  //使能USART1的时钟    
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //使能GPIOA的时钟
  
  //配置TX的GPIO 
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;               //设置TX的引脚
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;          //设置TX的模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         //设置TX的I/O口输出速度
  GPIO_Init(GPIOA, &GPIO_InitStructure);                    //根据参数初始化TX的GPIO
  
  //配置RX的GPIO
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10;              //设置RX的引脚
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;    //设置RX的模式
  GPIO_Init(GPIOA, &GPIO_InitStructure);                    //根据参数初始化RX的GPIO
  
  //配置USART的参数
  USART_StructInit(&USART_InitStructure);                   //初始化USART_InitStructure
  USART_InitStructure.USART_BaudRate   = bound;             //设置波特率
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;   //设置数据字长度
  USART_InitStructure.USART_StopBits   = USART_StopBits_1;  //设置停止位
  USART_InitStructure.USART_Parity     = USART_Parity_No;   //设置奇偶校验位
  USART_InitStructure.USART_Mode       = USART_Mode_Rx | USART_Mode_Tx;           //设置模式
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //设置硬件流控制模式
  USART_Init(USART1, &USART_InitStructure);                 //根据参数初始化USART1

  //配置NVIC
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;         //中断通道号
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //设置抢占优先级
  NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 1; //设置子优先级
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //使能中断
  NVIC_Init(&NVIC_InitStructure);                           //根据参数初始化NVIC

  //使能USART1及其中断
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  //使能接收缓冲区非空中断
  USART_ITConfig(USART1, USART_IT_TXE,  ENABLE);  //使能发送缓冲区空中断
  USART_Cmd(USART1, ENABLE);                      //使能USART1
                                                                     
  s_iUARTTxSts = UART_STATE_OFF;  //串口发送数据状态设置为未发送数据
}

/*********************************************************************************************************
* 函数名称:EnableUARTTx
* 函数功能:使能串口发送,在WriteUARTx中调用,即每次发送数据之后需要调用这个函数来使能发送中断 
* 输入参数:void
* 输出参数:void
* 返 回 值:void 
* 创建日期:2018年01月01日
* 注    意:s_iUARTTxSts = UART_STATE_ON;这句话必须放在USART_ITConfig之前,否则会导致中断打开无法执行
*********************************************************************************************************/
static  void  EnableUARTTx(void)
{
  s_iUARTTxSts = UART_STATE_ON;                     //串口发送数据状态设置为正在发送数据

  USART_ITConfig(USART1, USART_IT_TXE, ENABLE);     //使能发送中断
}

/*********************************************************************************************************
* 函数名称:SendCharUsedByFputc
* 函数功能:发送字符函数,专由fputc函数调用  
* 输入参数:ch,待发送的字符
* 输出参数:void
* 返 回 值:void 
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
static  void  SendCharUsedByFputc(u16 ch)
{  
  USART_SendData(USART1, (u8)ch);

  //等待发送完毕
  while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
  {
    
  }
}

/*********************************************************************************************************
* 函数名称:USART1_IRQHandler
* 函数功能:USART1中断服务函数 
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
void USART1_IRQHandler(void)                
{
  u8  uData = 0;

  if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收缓冲区非空中断
  {                                                         
    NVIC_ClearPendingIRQ(USART1_IRQn);  //清除USART1中断挂起
    uData = USART_ReceiveData(USART1);  //将USART1接收到的数据保存到uData
                                                          
    WriteReceiveBuf(uData);  //将接收到的数据写入接收缓冲区                                 
  }                                                         
                                                            
  if(USART_GetFlagStatus(USART1, USART_FLAG_ORE) == SET) //溢出错误标志为1
  {                                                         
    USART_ClearFlag(USART1, USART_FLAG_ORE);             //清除溢出错误标志
    USART_ReceiveData(USART1);                           //读取USART_DR 
  }                                                         
                                                           
  if(USART_GetITStatus(USART1, USART_IT_TXE)!= RESET)    //发送缓冲区空中断
  {                                                        
    USART_ClearITPendingBit(USART1, USART_IT_TXE);       //清除发送中断标志
    NVIC_ClearPendingIRQ(USART1_IRQn);                   //清除USART1中断挂起
                                                           
    ReadSendBuf(&uData);                                 //读取发送缓冲区的数据到uData
                                                                    
    USART_SendData(USART1, uData);                       //将uData写入USART_DR
                                                                                           
    if(QueueEmpty(&s_structUARTSendCirQue))              //当发送缓冲区为空时
    {                                                               
      s_iUARTTxSts = UART_STATE_OFF;                     //串口发送数据状态设置为未发送数据       
      USART_ITConfig(USART1, USART_IT_TXE, DISABLE);     //关闭串口发送缓冲区空中断
    }
  }
} 

/*********************************************************************************************************
*                                              API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:InitUART1
* 函数功能:初始化UART模块 
* 输入参数:bound,波特率
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
void InitUART1(u32 bound)
{
  InitUARTBuf();        //初始化串口缓冲区,包括发送缓冲区和接收缓冲区  
                  
  ConfigUART(bound);    //配置串口相关的参数,包括GPIO、RCC、USART和NVIC  
}

/*********************************************************************************************************
* 函数名称:WriteUART1
* 函数功能:写串口,即写数据到的串口发送缓冲区  
* 输入参数:pBuf,要写入数据的首地址,len,期望写入数据的个数
* 输出参数:void
* 返 回 值:成功写入数据的个数,不一定与形参len相等
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
u8  WriteUART1(u8 *pBuf, u8 len)
{
  u8 wLen = 0;  //实际写入数据的个数
                                                                  
  wLen = EnQueue(&s_structUARTSendCirQue, pBuf, len);

  if(wLen < UART1_BUF_SIZE)
  {
    if(s_iUARTTxSts == UART_STATE_OFF)
    {
      EnableUARTTx();
    }    
  }
                                                                  
  return wLen;  //返回实际写入数据的个数
}

/*********************************************************************************************************
* 函数名称:ReadUART1
* 函数功能:读串口,即读取串口接收缓冲区中的数据  
* 输入参数:pBuf,读取的数据存放的首地址,len,期望读取数据的个数
* 输出参数:pBuf,读取的数据存放的首地址
* 返 回 值:成功读取数据的个数,不一定与形参len相等
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
u8  ReadUART1(u8 *pBuf, u8 len)
{
  u8 rLen = 0;  //实际读取数据长度
                                                    
  rLen = DeQueue(&s_structUARTRecCirQue, pBuf, len);

  return rLen;  //返回实际读取数据的长度
}
    
/*********************************************************************************************************
* 函数名称:fputc
* 函数功能:重定向函数  
* 输入参数:ch,f
* 输出参数:void
* 返 回 值:int 
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
int fputc(int ch, FILE* f)
{
  SendCharUsedByFputc((u8) ch);  //发送字符函数,专由fputc函数调用
                               
  return ch;                     //返回ch
}

4.定时器

定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断

* 函数名称:ConfigTimer2
* 函数功能:配置TIM2 
* 输入参数:arr-自动重装值,psc-预分频器值
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:APB1时钟为36MHz,TIM2-TIM5时钟选择为APB1的2倍,因此,TIM2-TIM5时钟为72MHz
*********************************************************************************************************/
static  void ConfigTimer2(u16 arr, u16 psc)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;//TIM_TimeBaseStructure用于存放定时器的参数
  NVIC_InitTypeDef NVIC_InitStructure;           //NVIC_InitStructure用于存放NVIC的参数

  //使能RCC相关时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  //使能TIM2的时钟
  
  //配置TIM2
  TIM_TimeBaseStructure.TIM_Period        = arr;  //设置自动重装载值
  TIM_TimeBaseStructure.TIM_Prescaler     = psc;  //设置预分频器值
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;       //设置时钟分割:tDTS = tCK_INT
  TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up; //设置向上计数模式
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);               //根据参数初始化定时器
 
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);                    //使能定时器的更新中断

  //配置NVIC
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;               //中断通道号
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;     //设置抢占优先级
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;            //设置子优先级
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;               //使能中断
  NVIC_Init(&NVIC_InitStructure);                               //根据参数初始化NVIC
                                                                
  TIM_Cmd(TIM2, ENABLE);                                        //使能定时器  
}

/*********************************************************************************************************
* 函数名称:ConfigTimer5
* 函数功能:配置TIM5 
* 输入参数:arr-自动重装值,psc-预分频器值
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:APB1时钟为36MHz,TIM2-TIM5时钟选择为APB1的2倍,因此,TIM2-TIM5时钟为72MHz
*********************************************************************************************************/
static  void ConfigTimer5(u16 arr,u16 psc)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;//TIM_TimeBaseStructure用于存放定时器的参数
  NVIC_InitTypeDef NVIC_InitStructure;           //NVIC_InitStructure用于存放NVIC的参数

  //使能RCC相关时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);          //使能TIM5的时钟
  
  //配置TIM5
  TIM_TimeBaseStructure.TIM_Period        = arr;  //设置自动重装载值
  TIM_TimeBaseStructure.TIM_Prescaler     = psc;  //设置预分频器值 
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;       //设置时钟分割:tDTS = tCK_INT
  TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up; //设置向上计数模式
  TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);               //根据参数初始化定时器
 
  TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE);                      //使能定时器的更新中断

  //配置NVIC
  NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;               //中断通道号
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;     //设置抢占优先级
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;            //设置子优先级
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;               //使能中断
  NVIC_Init(&NVIC_InitStructure);                               //根据参数初始化NVIC 

  TIM_Cmd(TIM5, ENABLE);                                        //使能定时器
}

/*********************************************************************************************************
* 函数名称:TIM2_IRQHandler
* 函数功能:TIM2中断服务函数 
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:每毫秒进入一次中断服务函数
*********************************************************************************************************/
void TIM2_IRQHandler(void)  
{  
  static  u16 s_iCnt2 = 0;                            //定义一个静态变量s_iCnt2作为2ms计数器

  if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)     //判断定时器更新中断是否发生
  {
    TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);     //清除定时器更新中断标志
  }

  s_iCnt2++;            //2ms计数器的计数值加1
                                
  if(s_iCnt2 >= 2)      //2ms计数器的计数值大于或等于2
  {                                                   
    s_iCnt2 = 0;        //重置2ms计数器的计数值为0
    s_i2msFlag = TRUE;  //将2ms标志位的值设置为TRUE 
  }
}

/*********************************************************************************************************
* 函数名称:TIM5_IRQHandler
* 函数功能:TIM5中断服务函数 
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:每毫秒进入一次中断服务函数
*********************************************************************************************************/
void TIM5_IRQHandler(void)  
{
  static  i16 s_iCnt1000  = 0;                        //定义一个静态变量s_iCnt1000作为1s计数器

  if (TIM_GetITStatus(TIM5, TIM_IT_Update) == SET)    //判断定时器更新中断是否发生
  {
    TIM_ClearITPendingBit(TIM5, TIM_FLAG_Update);     //清除定时器更新中断标志 
  }                                                   
                                                      
  s_iCnt1000++;           //1000ms计数器的计数值加1
                                                      
  if(s_iCnt1000 >= 1000)  //1000ms计数器的计数值大于或等于1000
  {                                                   
    s_iCnt1000 = 0;       //重置1000ms计数器的计数值为0
    s_i1secFlag = TRUE;   //将1s标志位的值设置为TRUE
  } 
}

/*********************************************************************************************************
*                                              API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:InitTimer
* 函数功能:初始化Timer模块 
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:使用的TIM2-7由APB1(36MHz)预分频后输出。如果预分频为1,则由APB1*1输出,否则由APB1*2(72MHz)输出
*********************************************************************************************************/
void InitTimer(void)
{
  ConfigTimer2(999, 71);  //72MHz/(71+1)=1MHz,由0计数到999为1ms
  ConfigTimer5(999, 71);  //72MHz/(71+1)=1MHz,由0计数到999为1ms
}
static  void  Proc1SecTask(void)
{ 
  if(Get1SecFlag()) //判断1s标志状态
  {
    printf("This is the first STM32F103 Project, by Zhangsan\r\n");
    
    Clr1SecFlag();  //清除1s标志
  }    
}

5.系统节拍时钟

主要用于操作系统;这里只用于普通的定时器。

static  __IO  u32 s_iTimDelayCnt = 0;   //延时计数器s_iTimDelayCnt的初始值为0

/*********************************************************************************************************
*                                              内部函数声明
*********************************************************************************************************/
static  void TimDelayDec(void); //延时计数

/*********************************************************************************************************
*                                              内部函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:TimDelayDec
* 函数功能:延时计数  
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:在SysTick中断服务函数SysTick_Handler中调用
*********************************************************************************************************/
static  void TimDelayDec(void)
{
  if(s_iTimDelayCnt != 0) //延时计数器的数值不为0
  {                       
    s_iTimDelayCnt--;     //延时计数器的数值减1
  }
}

/*********************************************************************************************************
* 函数名称:SysTick_Handler
* 函数功能:SysTick中断服务函数 
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
void  SysTick_Handler(void)
{
  TimDelayDec();  //延时计数函数
}

/*********************************************************************************************************
*                                              API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:InitSysTick
* 函数功能:初始化SysTick模块  
* 输入参数:void  
* 输出参数:void  
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:SystemCoreClock / 1000      1ms中断一次(计数1000次为1s,每计一次位1/1000s=1ms)
*           SystemCoreClock / 4000      0.25ms中断一次(计数4000次为1s,每计一次位1/4000s=0.25ms)
*           SystemCoreClock / 100000    10us中断一次(计数100000次为1s,每计一次位1/100000s=10us)
*           SystemCoreClock / 1000000   1us中断一次(计数1000000次为1s,每计一次位1/1000000s=1us)
*********************************************************************************************************/
void InitSysTick( void )
{
  if (SysTick_Config(SystemCoreClock / 1000)) //配置系统滴答定时器1ms中断一次  
  { 
    while(1)  //错误发生的情况下,进入死循环
    {
      
    }
  }
}

/*********************************************************************************************************
* 函数名称:DelayNms
* 函数功能:毫秒级延时函数  
* 输入参数:nms
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
void  DelayNms(__IO u32 nms)
{
  s_iTimDelayCnt = nms;       //将延时计数器s_iTimDelayCnt的数值赋为nms
                              
  while(s_iTimDelayCnt != 0)  //延时计数器的数值为0时,表示延时了nms,跳出while语句
  {  
    
  }    
}

/*********************************************************************************************************
* 函数名称:DelayNus
* 函数功能:微秒级延时函数  
* 输入参数:nus
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:经测试,100us和200us基本准确
*********************************************************************************************************/
void  DelayNus(__IO u32 nus)    
{
  u32 s_iTimCnt = nus;     //定义一个变量s_iTimCnt作为延时计数器,赋值为nus
  u16 i;                   //定义一个变量作为循环计数器

  while(s_iTimCnt != 0)    //延时计数器s_iTimCnt的值不为0
  {
    for(i = 0; i < 7; i++) //空循环,产生延时功能
    {
    
    }
    
    s_iTimCnt--;           //成功延时1us,变量s_iTimCnt减1
  }    
}

6.RCC

时钟控制器,开启相应的外设时钟。(满足低功耗应用)

通过对HSE时钟的倍频,对AHB总线时钟的分频,对APB1总线和APB2总线时钟频率进行分配。

*******************************************************************************************************
*                                              内部函数实现
*********************************************************************************************************/

/*********************************************************************************************************
* 函数名称:ConfigRCC
* 函数功能:配置RCC 
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:配置的时钟如下:
*           (0)外部晶振HSE          = 8MHz
*           (1)PLLCLK(PLL时钟)    = HSE*9   = 72MHz
*           (2)SYSCLK(系统时钟)   = PLLCLK  = 72MHz
*           (3)HCLK(AHB总线时钟)  = SYSCLK  = 72MHz
*           (4)PCLK1(APB1总线时钟)= HCLK/2  = 36MHz
*           (5)PCLK2(APB2总线时钟)= HCLK    = 72MHz
*           (6)ADCCLK(ADC时钟)    = PCLK2/4 = 72/4 = 18MHz 
*********************************************************************************************************/
static void ConfigRCC(void)
{
  ErrorStatus HSEStartUpStatus;               //定义枚举变量HSEStartUpStatus,用来标志外部高速晶振的状态
  
  RCC_DeInit();                               //将外设RCC寄存器重设为默认值

  RCC_HSEConfig(RCC_HSE_ON);                  //使能外部高速晶振

  HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部高速晶振稳定
  
  if(HSEStartUpStatus == SUCCESS)             //外部高速晶振成功稳定   
  {
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能flash预读取缓冲区

    FLASH_SetLatency(FLASH_Latency_2);        //设置代码延时值,FLASH_Latency_2,2延时周期
  
    RCC_HCLKConfig(RCC_SYSCLK_Div1);          //设置高速AHB时钟(HCLK),RCC_SYSCLK_Div1,HCLK = SYSCLK 
  
    RCC_PCLK2Config(RCC_HCLK_Div1);           //设置高速APB2时钟(PCLK2),RCC_HCLK_Div1,PCLK2 = HCLK

    RCC_PCLK1Config(RCC_HCLK_Div2);           //设置低速APB1时钟(PCLK1),RCC_HCLK_Div2,PCLK1 = HCLK/2

    //RCC_ADCCLKConfig(RCC_PCLK2_Div4);       //设置ADC时钟(ADCCLK),RCC_PCLK2_Div4,ADCCLK = PCLK2/4 
  
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);//设置PLL时钟源及倍频系数,PLLCLK = 8MHz*9 = 72MHz

    RCC_PLLCmd(ENABLE);                       //使能PLL

    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)  //等待锁相环输出稳定
    {
      
    }

    //设置HSI/HSE/PLL为系统时钟
    //RCC_SYSCLKSource_HSI
    //RCC_SYSCLKSource_HSE
    //RCC_SYSCLKSource_PLLCLK
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);         //将锁相环输出设置为系统时钟

    //等待HSI/HSE/PLL成功用于系统时钟的时钟源
    //0x00-HSI作为系统时钟
    //0x04-HSE作为系统时钟
    //0x08-PLL作为系统时钟
    while(RCC_GetSYSCLKSource() != 0x08)               //等待PLL成功用于系统时钟的时钟源
    {
      
    }
  }
}

/*********************************************************************************************************
*                                              API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称:InitRCC
* 函数功能:初始化RCC模块 
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:
*********************************************************************************************************/
void InitRCC(void)
{
  ConfigRCC();  //配置RCC
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值