#蓝桥杯嵌入式#主观题精简知识点

中断函数标号(IRQHandler)在startup_stm32f10x_md.s中 NVIC在misc.c中
GPIO:参考代码:Project->STM32F10x_StdPeriph_Examples->GPIO->IOToggle

LED

  • 参考代码:Project->STM32F10x_StdPeriph_Examples->GPIO->IOToggle
  • 由于我们用到了PC和PD,因此GPIO初始化时也要初始化GPIOC和GPIOD,给的例程即GPIOD的配置,类似的,配置GPIOC即可
void led_Control(uint16_t led, uint8_t state)
{
	if(state==1)
	{
		GPIO_ResetBits(GPIOC,led);
		GPIO_SetBits(GPIOD,GPIO_Pin_2);
		GPIO_ResetBits(GPIOD,GPIO_Pin_2);
	}
	else if(state==0)
	{
		GPIO_SetBits(GPIOC,led);
		GPIO_SetBits(GPIOD,GPIO_Pin_2);
		GPIO_ResetBits(GPIOD,GPIO_Pin_2);
	}
}
//读取状态:
if(GPIO_ReadInputDataBit(GPIOC,led))
		state = 1;

Key

  • 参考例程:Project->STM32F10x_StdPeriph_Examples->EXTI->EXTI_Config
  • 四个按键分别连接在:PA0/PA8/PB1/PB2
  • 循环扫描只需要配置GPIO即可
  • #define BTN1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
u8 key_Scan()
{
	static u8 key = 1;
	if(key==1 && (!BTN1||!BTN2||!BTN3||!BTN4))
	{
		Delay_Ms(10);
		key = 0;
		if(!BTN1)
			return 1;
		else if(!BTN2)
			return 2;
		else if(!BTN3)
			return 3;
		else if(!BTN4)
			return 4;
	}
	else if(BTN1&&BTN2&&BTN3&&BTN4)
	{
		key = 1;
	}
	return 0;
}

按键消抖

  • 查看SysTick_Config的函数原型
  • 修改优先级
static __INLINE uint32_t SysTick_Config1(uint32_t ticks);
  //NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */
  NVIC_SetPriority (SysTick_IRQn, 1);

Buzzer

  • 参考例程:Project->STM32F10x_StdPeriph_Examples->GPIO->IOToggle
  • 连接在 了PB4引脚,PB4引脚默认是作为JTAG接口的RST引脚,因此在使用蜂鸣器之前要先把PB4复用回我们的普通IO口
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST,ENABLE);
    

EXTI

  • 参考例程:Project->STM32F10x_StdPeriph_Examples->EXTI->EXTI_Config
//这里是设置优先级,为0-15,初始15位最低级,所以将其优先级提高
//  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
//  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
  • 中断函数名在startup_stm32f10x_md.s,如EXTI9_5_IRQHandlerEXTI15_10_IRQHandler
  • 在几号端口就在几号中断线上,如PA0在0号中断线上。
//PA0
void EXTI0_IRQHandler(void)
{
  Delay_Ms(5);
  if(EXTI_GetITStatus(EXTI_Line0) != RESET)
  {
		if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_8))
			led_Control(LED1,1);
		else
			led_Control(LED1,0);
    EXTI_ClearITPendingBit(EXTI_Line0);
  }
}
  • main函数加NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2)
  • 注意加misc.c

LCD

参考官方例程。
记得在STM3210B_LCD_Init()函数后增加一个延时,建议延时500ms,因为对外设的操作没有我们MCU内部执行速度那么快。

u8 str[20];
u8 n = 1;
	
sprintf((char*)str,"n=%d",n);
LCD_DisplayStringLine(Line2,str);

UART

  • 参考例程:Project->STM32F10x_StdPeriph_Examples->USART->Interrupt
  • 复制里面的USART,GPIO,NVIC
  • 要把misc.c和 stm32f10x_usart.c文件也加进来
	//USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
	//这句不能写!因为是“发送寄存器空”的中断,所以发完字符串后必须关掉,否则只要空了,就会进中断
	//因此,只用写上一句RXNE的即可
/* Configure USARTy Rx as input floating */
	//RX为浮空输入
	//RX2连接PA3引脚,因此把原句中USARTy_RxPin改成具体引脚:GPIO_Pin_3
    //GPIO_InitStructure.GPIO_Pin = USARTy_RxPin;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  
    /* Configure USARTy Tx as alternate function push-pull */
    //Tx为推挽复用
    //TX2连接PA2引脚,因此把原句中USARTy_RxPin改成具体引脚:GPIO_Pin_2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
//上面GPIO这一段直接复制,改改引脚即可

    /* Enable the USARTy Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    //注:这个的配置库函数没有,但是EXIT中断那边有,所以还是写上
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
  • 串口发送函数
void SendString(char *str)
{
	while(*str)
	{
		USART_SendData(USART2,*str++);
		while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
	}
}
  • 串口调试时,WIN+R键运行,输入devmgmt.msc打开设备管理器,查看USART是哪个串口

IIC

  • 参考例程:底层驱动代码参考文件夹
  • 参考文件:AT24C02.pdf 11页 Figure8和Figure11
  • 添加E2PROM的读写驱动代码
void E2PROM_Write(u8 add, u8 data)
{
	I2CStart();
	
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(add);
	I2CWaitAck();
	
	I2CSendByte(data);
	I2CWaitAck();
	
	I2CStop();
}

u8 E2PROM_Read(u8 add)
{
	u8 data;
	
	I2CStart();
	
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(add);
	I2CWaitAck();
	
	I2CStart();
	
	I2CSendByte(0xa1);
	I2CWaitAck();
	
	data = I2CReceiveByte();
	I2CSendAck();
	
	return data;
}
  • 读写一个u32类型的数据
void x24_write_int(u8 add, int data)
{
	x24_write(add,(u8)(data&0xff));
	delay_ms(2);
	x24_write(add+1,(u8)(data>>8&0xff));
	delay_ms(2);
	x24_write(add+2,(u8)(data>>16&0xff));
	delay_ms(2);
	x24_write(add+3,(u8)(data>>24&0xff));
	delay_ms(2);
}

int x24_read_int(u8 add)
{
	int data;
	data=(int)x24_read(add);
	delay_ms(2);
	data+=(int)x24_read(add+1)<<8;
	delay_ms(2);
	data+=(int)x24_read(add+2)<<16;
	delay_ms(2);
	data+=(int)x24_read(add+3)<<24;
	delay_ms(2);
	return data;
}
  • 主函数
isLight = E2PROM_Read(0x00);
E2PROM_Write(0x00, ++isLight);
sprintf((char*)tmp, "Data:%d", E2PROM_Read(0x00));
LCD_DisplayStringLine(Line4 ,tmp);
  • 连续读最好延时2ms,连续写延时5ms(建议都延时5ms)

ADC

  • 参考例程:Project->STM32F10x_StdPeriph_Examples->ADC->ADC1_DMA
  • 连接的是PB0 ,需要改GPIO配置和ADC通道
  • 一路中不需要启动连续转换模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC.c函数下:
u16 get_ADC(void)
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);如果一直要获取写在初始化函数中,如果通过按键获得写在函数中
	while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));
	return ADC_GetConversionValue(ADC1);
}

主函数:
	adc_Init();
	while(1)
	{
		value = 3.3 * get_ADC() / 4096;
		sprintf((char*)ADC, "PB0 Voltage:%.2f", value);
		LCD_DisplayStringLine(Line4 ,ADC);
		Delay_Ms(500);
	}

RTC

  • 参考例程1:Project->STM32F10x_StdPeriph_Examples->RTC->LSI_Calib下NVIC_Configuration()和RTC_Configuration()
  • 最后两行BKP_TamperPinCmd()和BKP_RTCOutputConfig()不要复制,LCD与RTC引脚复用,如果复制会因安全保护导致LCD不能显示
  • 参考例程2:Project->STM32F10x_StdPeriph_Examples->RTC->Calendar
    • 复制Time_Adjust()函数,把Time_Regulate()函数中的return代入
    • 复制Time_Display()函数,函数参数用u32变量RTC_GetCounter()代替
  • 复制中断函数,并把Time_Display()函数中的23:59:59置0写到中断函数中
  • 两位整数输出0.2d
void RTC_IRQHandler(void)
{
  if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
  {
    RTC_ClearITPendingBit(RTC_IT_SEC);
		if (RTC_GetCounter() == 0x0001517F)
		{
			RTC_SetCounter(0x0);
			RTC_WaitForLastTask();
		}
  }
}

void Time_Adjust(u8 Tmp_HH,u8 Tmp_MM,u8 Tmp_SS )
{
  RTC_WaitForLastTask();
  RTC_SetCounter((Tmp_HH*3600 + Tmp_MM*60 + Tmp_SS));
  RTC_WaitForLastTask();
}

u8 buffer[20];
void Time_Display()
{
  uint32_t THH = 0, TMM = 0, TSS = 0, TimeVar = RTC_GetCounter();
  
  /* Compute  hours */
  THH = TimeVar / 3600;
  /* Compute minutes */
  TMM = (TimeVar % 3600) / 60;
  /* Compute seconds */
  TSS = (TimeVar % 3600) % 60;

  sprintf((char*)buffer,"Time: %0.2d:%0.2d:%0.2d", THH, TMM, TSS);
	LCD_DisplayStringLine(Line4,buffer);
}
  • 注:需要加上stm32f10x_rtc.c,stm32f10x_bkp.c,stm32f10x_pwr.c,misc.c

TIM

  • 参考例程:Project->STM32F10x_StdPeriph_Examples->TIM->TimeBase下main.c
    • 复制①RCC_Configuration();不用选分频
    • ②NVIC_Configuration();
    • ③/* Time base configuration */并把Period改成999,Prescaler改成71。即定时器1ms进入一次中断。
    • ④TIM_ITConfig(TIM2,TIM_IT_Update, ENABLE);改成Update
    • ⑤TIM_Cmd();配置为1ms中断
  • 然后写中断函数
    //TIM_IT_Update
    u8 status = 0;
    u16 cnt = 0;
    void TIM2_IRQHandler(void)
    {
      if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
      {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    		if(cnt++ == 500)
    		{
    			cnt = 0;
    			led_Control(LED_ALL, status);
    			status = !status;
    		}
      }
    

PWM

OC之固定频率、可变占空比

  • 参考例程:Project->STM32F10x_StdPeriph_Examples->TIM->PWM_Output
    • 将初始化函数加两个参数:u32 freq,u8 duty
    • 复制其中的/* Time base configuration */部分内容,并把Period设为arr(arr=1000000/freq-1),Prescale设为71
    • 复制其中/* PWM1 Mode configuration: Channel1 */部分内容,加上TIM_ARRPreloadConfig()TIM_Cmd(),加上脉冲TIM_OCInitStructure.TIM_Pulse = (arr+1)*duty/100;
    • 复制RCC_Configuration(void)
  • 去TIM配置那复制NVIC,修改优先级
  • 用TIM_SetCompareX(TIM3,Pulse)改变占空比。

OC之可变频率、可变占空比

  • 参考例程:Project->STM32F10x_StdPeriph_Examples->TIM->OCToggle
    • 复制全局变量定义,自己修改CCRx_Val=频率为72M/72/频率=1000000/频率
    • TIM初始化:TIM_Period = 65535
    • TIM_OC初始化
    • 时钟使能
    • GPIO的配置(PA6和PA7)
    • NVIC_Configuration()
  • 中断处理函数:(定义一个变量分别执行下列函数)
capture = TIM_GetCapture1(TIM3);
TIM_SetCompare1(TIM3, capture + (u16)CCR1_Val *zhankong1 );
TIM_SetCompare1(TIM3, capture + (u16)CCR1_Val *(1-zhankong1));
  • 完整代码:
__IO uint16_t CCR1_Val = 100;//72000000/72/10000
__IO uint16_t CCR2_Val = 1000;//72000000/72/1000
float zhankong1 = 0.1, zhankong2 = 1;
uint16_t capture = 0;
u8 pa6_state = 0,pa7_state = 0;
void TIM3_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
  {
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC1 );
    capture = TIM_GetCapture1(TIM3);
	if(pa6_state == 0)
	{
		TIM_SetCompare1(TIM3, capture + (u16)CCR1_Val * zhankong1 );
		pa6_state = 1;
	}
	else
	{
		TIM_SetCompare1(TIM3, capture + (u16)CCR1_Val * (1 - zhankong1));
		pa6_state = 0;
	}
  }
  if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)
  {
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
    capture = TIM_GetCapture2(TIM3);
    if(pa7_state == 0)
	{
		TIM_SetCompare2(TIM3, capture + (u16)CCR2_Val * zhankong2 );
		pa7_state = 1;
	}
	else
	{
		TIM_SetCompare2(TIM3, capture + (u16)CCR2_Val * (1 - zhankong2));
		pa7_state = 0;
	}
  }
}

IC之一路PWM的频率和占空比

  • 参考例程:Project->STM32F10x_StdPeriph_Examples->TIM->PWM_Input
    • TIM_IC初始化
    • RCC_Configuration()
    • GPIO_Configuration()
    • NVIC_Configuration()
  • stm32f10x_it.c下中断处理函数

IC之两路PWM的频率和占空比

  • 参考例程:Project->STM32F10x_StdPeriph_Examples->TIM->InputCapture
    • TIM_IC初始化:TIM_ICInitStructure.TIM_Channel = TIM_Channel_1|TIM_Channel_2;)以及(TIM_ITConfig(TIM3, TIM_IT_CC1|TIM_IT_CC2, ENABLE);
    • RCC_Configuration();
    • NVIC_Configuration();
    • GPIO_Configuration();加上GPIO_Pin_6
  • 要加上定时器TIM_TimeBaseInitTypeDef初始化代码"Project->STM32F10x_StdPeriph_Examples->TIM->OCToggle"
    • TIM_Prescaler=71;
    • TIM_Period = 65535;
  • 如果不求占空比,直接用例程代码。
  • 若是考虑占空比的计算以及两路PWM,那这里的例程和全局变量仅能做一个参考,需要我们自己完善
__IO uint16_t IC3ReadValue1 = 0, IC3ReadValue2 = 0;//
__IO uint16_t DutyCycleValue1 = 0,DutyCycleValue2 = 0;
__IO uint16_t CaptureNumber = 0,CaptureNumber_DC = 0;//捕获计数
__IO uint32_t Capture = 0,Capture_DC = 0;//捕获时间,DC表示下降沿捕获时间
__IO uint32_t TIM3Freq = 0,TIM3DutyCycle = 0;//频率和占空比

__IO uint16_t _IC3ReadValue1 = 0, _IC3ReadValue2 = 0;
__IO uint16_t _DutyCycleValue1 = 0,_DutyCycleValue2 = 0;
__IO uint16_t _CaptureNumber = 0,_CaptureNumber_DC = 0;
__IO uint32_t _Capture = 0,_Capture_DC = 0;
__IO uint32_t _TIM3Freq = 0,_TIM3DutyCycle = 0;
void TIM3_IRQHandler(void)
{ 
	//采用定时器溢出中断,不管定时器频率如何变化,总是会出现定时器溢出中断更新不及时的情况,即计数值已重新技术到比0大的值,但定时器溢出中断未产生
	if(TIM_GetITStatus(TIM3, TIM_IT_CC1) == SET) //捕获1发生捕获事件
	{
    	TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);//清楚中断标志位
		if(_CaptureNumber_DC == 0)
		{
			//捕获到上升沿,计算时间
			_DutyCycleValue1 = TIM_GetCapture1(TIM3);
			if(_CaptureNumber == 0)
			{
				_IC3ReadValue1 = _DutyCycleValue1;
				_CaptureNumber = 1;
			}
			else if(_CaptureNumber == 1)
			{
				_IC3ReadValue2 = _DutyCycleValue1; 
				if (_IC3ReadValue2 > _IC3ReadValue1)
					_Capture = (_IC3ReadValue2 - _IC3ReadValue1); 
				else
					_Capture = ((0xFFFF - _IC3ReadValue1) + _IC3ReadValue2); 
				_TIM3Freq = (uint32_t) SystemCoreClock / _Capture;
				_CaptureNumber = 0;
			}
			TIM_OC1PolarityConfig(TIM3, TIM_ICPolarity_Falling);
			_CaptureNumber_DC = 1;
		}
		else if(_CaptureNumber_DC==1)
		{
			_DutyCycleValue2 = TIM_GetCapture1(TIM3);
			if (_DutyCycleValue2 > _DutyCycleValue1)
				_Capture_DC = (_DutyCycleValue2 - _DutyCycleValue1); 
			else
				_Capture_DC = ((0xFFFF - _DutyCycleValue1) + _DutyCycleValue2); 
			//计算占空比=下降沿捕获时间/总捕获时间
			_TIM3DutyCycle = _Capture_DC/_Capture;
			//设置为上升沿捕获
			TIM_OC1PolarityConfig(TIM3, TIM_ICPolarity_Rising);
			_CaptureNumber_DC = 0;
		}
  }
	/*Initialize TIM3 CC2 IT*/
	if(TIM_GetITStatus(TIM3, TIM_IT_CC2) == SET) 
	{
  		TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
		if(CaptureNumber_DC == 0)
		{
			DutyCycleValue1 = TIM_GetCapture2(TIM3);
			if(CaptureNumber == 0)
			{
				IC3ReadValue1 = DutyCycleValue1;
				CaptureNumber = 1;
			}
			else if(CaptureNumber == 1)
			{
				IC3ReadValue2 = DutyCycleValue1; 
				if (IC3ReadValue2 > IC3ReadValue1)
					Capture = (IC3ReadValue2 - IC3ReadValue1); 
				else
					Capture = ((0xFFFF - IC3ReadValue1) + IC3ReadValue2); 
				TIM3Freq = (uint32_t) SystemCoreClock / Capture;
				CaptureNumber = 0;
			}
			TIM_OC2PolarityConfig(TIM3, TIM_ICPolarity_Falling);
			CaptureNumber_DC = 1;
		}
		else if(CaptureNumber_DC==1)
		{
			DutyCycleValue2 = TIM_GetCapture2(TIM3);
			if (DutyCycleValue2 > DutyCycleValue1)
				Capture_DC = (DutyCycleValue2 - DutyCycleValue1); 
			else
				Capture_DC = ((0xFFFF - DutyCycleValue1) + DutyCycleValue2); 
			TIM3DutyCycle = Capture_DC/Capture;
			TIM_OC2PolarityConfig(TIM3, TIM_ICPolarity_Rising);
			CaptureNumber_DC = 0;
		}
	}
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值