文章目录
中断函数标号(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_IRQHandler
和EXTI15_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_IC初始化:
- 要加上定时器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;
}
}
}