本届试题主要考察PWM的捕获与输出;难度较大;
①、库文件
②、中断服务函数
u8 flag=0,count=0;
void USART2_IRQHandler(void)
{
u8 temp;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
temp= USART_ReceiveData(USART2);
if(temp=='S')
{
RX_Buff[count]=temp;
flag=1;
count++;
}
else if(flag==1)
{
RX_Buff[count]=temp;
count++;
if(count==8)
{
Receive=1;
flag=0;
count=0;
}
}
}
}
void TIM2_IRQHandler(void) //注意是定时器2
{
if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET)
{
/* Clear TIM3 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
/* Get the Input Capture value */
IC2ReadValue1 = TIM_GetCapture2(TIM2); //通道二
if(IC2ReadValue1 != IC2ReadValue2) //输入捕获通道2变化
{
Capt1=IC2ReadValue1-IC2ReadValue2;
TIM2_Fre1=100000/Capt1; //得到频率1
}
if(TIM2_Fre1 == 0) //如果是0,则 使其保留上一个值,这样做可以保证数值的稳定性
{
TIM2_Fre1 =TIM2_Fre1_Last ;
}
TIM2_Fre1_Last =TIM2_Fre1;
IC2ReadValue2=IC2ReadValue1 ;
IC2_Flag=1 ;
}
if(TIM_GetITStatus(TIM2, TIM_IT_CC3) == SET)
{
/* Clear TIM3 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
/* Get the Input Capture value */
IC2ReadValue1 = TIM_GetCapture3(TIM2); //通道二
if(IC3ReadValue1!= IC3ReadValue2) //输入捕获通道2变化
{
Capt2=IC2ReadValue1-IC2ReadValue2;
TIM2_Fre2=100000/Capt2; //得到频率1
}
if(TIM2_Fre2 == 0) //如果是0,则 使其保留上一个值,这样做可以保证数值的稳定性
{
TIM2_Fre2 =TIM2_Fre2_Last ;
}
TIM2_Fre2_Last =TIM2_Fre2;
IC3ReadValue2=IC3ReadValue1 ;
IC3_Flag=1;
}
}
uint16_t capture = 0;
void TIM3_IRQHandler(void)
{
/* TIM3_CH1 toggling with frequency = 183.1 Hz */
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1 );
capture = TIM_GetCapture1(TIM3);
TIM_SetCompare1(TIM3, capture + CCR1_Val );
if(PA6_Out==1)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_6,(BitAction)(1-GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)));
}
else
{
GPIO_WriteBit(GPIOA,GPIO_Pin_6,(BitAction)0); //输出低电平
}
}
/* TIM3_CH2 toggling with frequency = 366.2 Hz */
if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
capture = TIM_GetCapture2(TIM3);
TIM_SetCompare2(TIM3, capture + CCR2_Val);
if(PA7_Out==1)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_7,(BitAction)(1-GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7)));
}
else
{
GPIO_WriteBit(GPIOA,GPIO_Pin_7,(BitAction)0); //输出低电平
}
}
}
③、初始化
#include "stm32f10x.h"
#include <stdio.h>
#include "i2c.h"
#include "lcd.h"
#include "init.h"
void LCD_Init(void)
{
STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
LCD_DisplayStringLine(Line0," ");
LCD_DisplayStringLine(Line1," ");
LCD_DisplayStringLine(Line2," Channel(1): 1000Hz ");
LCD_DisplayStringLine(Line3," ");
LCD_DisplayStringLine(Line4," N(1): 1 ");
LCD_DisplayStringLine(Line5," ");
LCD_DisplayStringLine(Line6," Channel(2): 3000Hz ");
LCD_DisplayStringLine(Line7," ");
LCD_DisplayStringLine(Line8," N(2): 3 ");
LCD_DisplayStringLine(Line9," ");
}
void GPIO_Int(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC, ENABLE);
//led
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10| GPIO_Pin_11| GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;
GPIO_Init(GPIOD, &GPIO_InitStructure);
//key
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10| GPIO_Pin_11| GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15);
GPIO_SetBits(GPIOD,GPIO_Pin_2);
GPIO_ResetBits(GPIOD,GPIO_Pin_2);
NVIC_Configuration();
}
void TIM2_Init(void)
{
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* TIM2 channel 2 pin (PA.07) configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = 0xffff; //设置在下一个更新事件装入活动的自动重装载寄存
TIM_TimeBaseStructure.TIM_Prescaler = 71;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ICInit(TIM2, &TIM_ICInitStructure);
/* TIM enable counter */
TIM_Cmd(TIM2, ENABLE);
/* Enable the CC2 Interrupt Request */
TIM_ITConfig(TIM2, TIM_IT_CC2|TIM_IT_CC3, ENABLE);//通道2,3中断开启
/*要测量输入PWM的频率与占空比,首先需要初始化定时器的定时时基,
上面的代码设置定时周期TIM_Period为0xFFFF,即65535,设置定时预分频TIM_Prescaler为71,
即72分频,所以计数没每递增一次就需要1/1000000s。
定时器会从0开始到65535计时,当检测到上升沿或下降沿就会保存当前的计数值,
然后根据计数值计算出频率(下文会讲到)。这里需要注意的地方时,
由于我设置了TIM_Period为0xFFFF,TIM_Prescaler为71,
对测量的频率范围也有规定,计数值只能是0~65535,
所以频率的范围为1000000/63336=15Hz,即能测量的最小频率为15Hz,
小于15Hz的频率测量将不准确。如果想测量小于15的频率,可以将定时器分频增大,
所以只要设置预分频TIM_Prescaler就可以调整能测量的最小频率了
但同时,如果分频过大,则导致测量的结果不稳定,一直变化
*/
}
void TIM3_Init(void) //为了输出不同频率的pwm需要设置比较输出模式
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* GPIOA Configuration:TIM3 Channel1, as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出,否则引脚无电流
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 65535; //必须这个值
TIM_TimeBaseStructure.TIM_Prescaler = 71;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
/*TIM_OCMode_Timing是在比较成功后不在对应输出管脚上产生输出。
TIM_OCMode_Toggle是在比较成功后翻转对应输出管脚上的电平。*/
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);//disable
/* PWM1 Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);
TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2, ENABLE);
/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE);
}
void USART2_Init(void)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2|RCC_APB2Periph_GPIOA, ENABLE); //注意usart是apb1
USART_InitStructure.USART_BaudRate = 9600;
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的接收功能
/* Configure USART2 */
USART_Init(USART2, &USART_InitStructure);
/* Enable USART2 Receive */
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
/* Enable the USARTz */
USART_Cmd(USART2, ENABLE);
GPIO_InitStructure.GPIO_Pin = USARTz_RxPin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void NVIC_Configuration(void) //不要遗漏,否则无法启动中断服务函数
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
/* Enable the USART2 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
unsigned char IIC_Read(unsigned char add)
{
unsigned char temp;
I2CStart();
I2CSendByte(0xa0);
I2CSendAck();
I2CSendByte(add);
I2CSendAck();
I2CStart();
I2CSendByte(0xa1);
I2CSendAck();
temp=I2CReceiveByte();
I2CSendAck();
I2CStop();
return (temp);
}
void IIC_Write(unsigned char add,unsigned char dat)
{
I2CStart();
I2CSendByte(0xa0);
I2CSendAck();
I2CSendByte(add);
I2CSendAck();
I2CSendByte(dat);
I2CSendAck();
I2CStop();
}
④、主函数
#include "stm32f10x.h"
#include <stdio.h>
#include "i2c.h"
#include "lcd.h"
#include "init.h"
u32 TimingDelay = 0;
void Delay_Ms(u32 nTime);
void Key_Scan(void);
void LED_Run(u16 run);
u8 N1,N2;
u8 string[20];
u8 RX_Buff[20];
u8 Receive=0;
u16 run=0xffff;
u8 qie=0;
u8 bengdi=0;
u8 PA6_Out=0,PA7_Out=0;
__IO uint16_t CCR1_Val = 1000;
__IO uint16_t CCR2_Val = 200;
u32 IC2ReadValue1=0,IC2ReadValue2=0,IC3ReadValue1=0,IC3ReadValue2=0;
u32 Capt1=0,Capt2=0;
u8 IC2_Flag=0, IC3_Flag=0;
u32 TIM2_Fre1=0,TIM2_Fre1_Last=0,TIM2_Fre2=0,TIM2_Fre2_Last=0;
int main(void)
{
SysTick_Config(SystemCoreClock/1000);
LCD_Init();
GPIO_Int();
i2c_init(); //注意不要漏
USART2_Init();
//run=run&0xfbff;//默认usart open led3
// TIM3_Init();
// TIM2_Init();
if(IIC_Read(0x20)!=20)
{
Delay_Ms(5);
IIC_Write(0x00,2);
Delay_Ms(5);
IIC_Write(0x01,2);
Delay_Ms(5);
IIC_Write(0x20,20);
}
Delay_Ms(5); //注意延时,否则读取不正确
N1=IIC_Read(0x00);
Delay_Ms(5);
N2=IIC_Read(0x01);
sprintf((char*)string," N(1): %d ",N1);
LCD_DisplayStringLine(Line4,string);
sprintf((char*)string," N(2): %d ",N2);
LCD_DisplayStringLine(Line8,string);
while(1)
{
Key_Scan();
LED_Run(run);
if(Receive==1)
{
Receive=0;
LCD_DisplayStringLine(Line0,RX_Buff);
if(RX_Buff[4]-48==1)
{
N1= RX_Buff[6]-48+RX_Buff[7]-48;
sprintf((char*)string," N(1): %.2dHz ",N1);
Delay_Ms(5);
IIC_Write(0x00,N1);
LCD_DisplayStringLine(Line4,string);
}
else if(RX_Buff[4]-48==2)
{
N2= RX_Buff[6]-48+RX_Buff[7]-48;
sprintf((char*)string," N(2): %.2dHz ",N2);
Delay_Ms(5);
IIC_Write(0x01,N2);
LCD_DisplayStringLine(Line8,string);
}
}
if(IC2_Flag==1)
{
IC2_Flag=0;
sprintf((char*)string,"Freq1: %.2dHz ",TIM2_Fre1);
LCD_DisplayStringLine(Line3,string);
if((TIM2_Fre1>=50)&&(TIM2_Fre1<=50000)) //注意括号,下同
{
run=run&0xfeff; //open led1
CCR1_Val=500000/TIM2_Fre1/N1;//倍频输出
PA6_Out=1;
}
else
{
run=run|0100; //close led1
PA6_Out=0;
}
}
else
{
run=run|0x0100;
PA6_Out=0;
}
if(IC3_Flag==1)
{
IC3_Flag=0;
sprintf((char*)string,"Freq2: %d ",TIM2_Fre2);
LCD_DisplayStringLine(Line5,string);
if((TIM2_Fre2>=50)&&(TIM2_Fre2<=50000))
{
run=run&0xfdff; //open led2
CCR2_Val=500000/TIM2_Fre2/N2;//倍频输出
PA6_Out=1;
}
else
{
run=run|0200; //close led2
PA7_Out=1;
}
}
else
{
run=run|0200; //close led2
PA7_Out=1;
}
}
}
void Key_Scan(void)
{
if(RB1==0)
{
Delay_Ms(5);
if(RB1==0)
{
if(bengdi==0)
{
bengdi=1;qie=1;
LCD_DisplayStringLine(Line9," 1");
USART_Cmd(USART2, DISABLE);
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, DISABLE); //默认开启usart,第一次按键关闭usart
run=run|0x0400; //close led3
}
else if(bengdi==1)
{
bengdi=0;
USART2_Init();
LCD_DisplayStringLine(Line9," usart");
run=run&0xfbff; //open led3
}
}while(!RB1);
}
else if(RB2==0)
{
Delay_Ms(5);
if(RB2==0)
{
if(bengdi==1)
{
if(qie==1)
{
qie=2;
LCD_DisplayStringLine(Line9," 2");
}
else if(qie==2)
{
qie=1;
LCD_DisplayStringLine(Line9," 1");
}
}
} while(!RB2);
}
else if(RB3==0)
{
Delay_Ms(5);
if(RB3==0)
{
if(bengdi==1)
{
if(qie==1)
{
N1-=1;
if(N1<1)
N1=1;
sprintf((char*)string," N(1): %d ",N1);
LCD_DisplayStringLine(Line4,string);
Delay_Ms(5);
IIC_Write(0x00,N1);
}
else if(qie==2)
{ +
N2--;
if(N2<1)
N2=1;
sprintf((char*)string," N(2): %d ",N2);
LCD_DisplayStringLine(Line8,string);
Delay_Ms(5);
IIC_Write(0x01,N2);
}
}
} while(!RB3);
}
else if(RB4==0)
{
Delay_Ms(5);
if(RB4==0)
{
if(bengdi==1)
{
if(qie==1)
{
N1+=1;
if(N1>10)
N1=10;
sprintf((char*)string," N(1): %d ",N1);
LCD_DisplayStringLine(Line4,string);
Delay_Ms(5);
IIC_Write(0x00,N1);
}
if(qie==2)
{
N2+=1;
if(N2>10)
N2=10;
sprintf((char*)string," N(2): %d ",N2);
LCD_DisplayStringLine(Line8,string);
Delay_Ms(5);
IIC_Write(0x01,N2);
}
}
} while(!RB4);
}
}
void LED_Run(u16 run) //寄存器方法,开关灯
{
GPIO_SetBits(GPIOC,run);
GPIO_SetBits(GPIOD,GPIO_Pin_2);
GPIO_ResetBits(GPIOD,GPIO_Pin_2);
}
void Delay_Ms(u32 nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
因为题目要求pwm输出,默认输出两个频率不同的倍频,因而用到比较输出;其中需要注意的点已在文中标注;同时因为usart与pwm共用pa2,因而涉及到usart的失能;而本次为了使led灯便于控制,特地用寄存器版本写的,涉及位的与或运算。具体见程序。