代码下载地址
完成了所有要求功能
“双路输出控制器”具有信号输出时间设定、输出信号占空比调整、当前输出通道及时
间显示、系统工作参数存储、串口通讯及 LED 指示等功能。 “双路输出控制器”通过串口完
成信号输出时间设定功能;通过 EEPROM 完成系统工作参数存储功能;通过按键完成输出通
道切换、输出信号占空比调整及停止信号输出功能;系统硬件电路主要由 MCU 控制单元、独
立按键、LCD 显示单元、串口通讯单元、EEPROM 数据存储单元和 LED 指示单元组成,系统框
图如图 1 所示:
题目要求是:
使用外部终端判断按键按下,并进行相应处理:
usart2:
u8 K1=1;
u8 K3=1;
void KEY_Init()
{
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable GPIOA clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource8);
EXTI_InitStructure.EXTI_Line=EXTI_Line8;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_Init(&NVIC_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
EXTI_InitStructure.EXTI_Line=EXTI_Line1;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_Init(&NVIC_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource2);
EXTI_InitStructure.EXTI_Line=EXTI_Line2;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
NVIC_Init(&NVIC_InitStructure);
}
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
delay_ms(5);
if(KEY1==0)
{
if(K1==0)
{
K1=1;
TIM_SetCompare2(TIM2,A1_pwm);
}
else
{
K1=0;
TIM_SetCompare2(TIM2,0);
}
}//while(KEY1==0);
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
void EXTI9_5_IRQHandler(void)
{
u8 val;
if(EXTI_GetITStatus(EXTI_Line8) != RESET)
{
delay_ms(10);
if(KEY2==0)
{
if(A1_pwm<899)
{
A1_pwm+=90;
TIM_SetCompare2(TIM2,A1_pwm);
x24c02_write_u16(0X01,A1_pwm);
delay_ms(2);
}
}//while(KEY2==0);
EXTI_ClearITPendingBit(EXTI_Line8);
}
}
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1) != RESET)
{
delay_ms(5);
if(KEY3==0)
{
if(K3==0)
{
K3=1;
TIM_SetCompare3(TIM2,A2_pwm);
LED_Control(LED2,1);
}
else
{
K3=0;
TIM_SetCompare3(TIM2,0);
}
}//while(KEY3==0);
EXTI_ClearITPendingBit(EXTI_Line1);
}
}
void EXTI2_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line2) != RESET)
{
delay_ms(5);
if(KEY4==0)
{
if(A2_pwm<899)
{
A2_pwm+=90;
TIM_SetCompare3(TIM2,A2_pwm);
x24c02_write_u16(0X04,A2_pwm);
delay_ms(2);
}
}//while(KEY4==0);
EXTI_ClearITPendingBit(EXTI_Line2);
}
}
题目要求是:
系统可通过串口接收命令,用户输入字符串“hh:mm:ss-PAx-yS”,设定 PAx 通道在 hh
时 mm 分 ss 秒输出脉宽调制信号,持续输出 y 秒(10>y>0) 。使用 STM32 USART2 完成上述串口功能,并将通讯波特率设定为 9600。
[命令格式举例] - 通过串口输入“00:00:20-PA1-5S” ,即设定系统在 0 时 0 分 20 秒通过
PA1 通道持续输出脉宽调制信号,5 秒后输出低电平信号。
使用了usart2,来接收上位机传来的命令,再通过Timer4,每过0.5s判断一次命令是否需要执行
u8 usart_index=0;
u8 usart_receive=0;
u8 usart_str[20];
void USART2_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
/* Configure USARTy Rx as input floating */
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 */
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);
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_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_Cmd(USART2, ENABLE);
}
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')||(usart_index==20))
{
usart_str[usart_index]=temp;
usart_index=0;
usart_receive=1;
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
}
else
{
usart_str[usart_index]=temp;
++usart_index;
}
}
}
Timer3:
u8 flag_L2=0;
u8 str_com[20];
u8 command=0;
u8 fenxi=0;
u8 timedelay;
void TIM3_Init(u16 arr, u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler = psc;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3, ENABLE);
}
void TIM3_IRQHandler()
{
u8 i;
u8 str[20];
u8 same=0;
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
time=RTC_GetCounter();
if(usart_receive==1&&command==0)//½ÓÊÕÊÇ·ñÕýÈ·
{
if((usart_str[0]=='0'||'1')&&
(usart_str[1]=='0'||'1'||'2'||'3'||'4')&&
(usart_str[2]==':')&&
(usart_str[3]=='0'||'1'||'2'||'3'||'4'||'5')&&
(usart_str[4]=='0'||'1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'||'9')&&
(usart_str[5]==':')&&
(usart_str[6]=='0'||'1'||'2'||'3'||'4'||'5')&&
(usart_str[7]=='0'||'1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'||'9')&&
(usart_str[8]=='-')&&
(usart_str[9]=='P')&&
(usart_str[10]=='A')&&
(usart_str[11]=='1'||'2')&&
(usart_str[12]=='-')&&
(usart_str[13]=='1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'||'9')&&
(usart_str[14]=='S'))
{
command=1;
}
else
{
usart_index=0;
usart_receive=0;
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}
}
if(command==1&&fenxi==0)//·ÖÎö
{
sprintf(str,"%0.2d:%0.2d:%0.2d",time/3600,(time%3600)/60,(time%3600)%60);
for(i=0;i<8;i++)
{
if(str[i]==usart_str[i]) same=1;
else {same=0;break;}
}
if(same==1)
{
timedelay=(usart_str[13]-'0')*2;
fenxi=1;
}
}
if(fenxi==1)//Ö´ÐÐ
{
timedelay--;
if(timedelay==0)
{
if(usart_str[11]=='1')
{
K1=1;
TIM_SetCompare2(TIM2,A1_pwm);
}
else if(usart_str[11]=='2')
{
K3=1;
TIM_SetCompare3(TIM2,A2_pwm);
}
fenxi=0;
usart_receive=0;
command=0;
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}
}
if(flag_L2==1){LED_Control(LED8,1);flag_L2=0;}
else{LED_Control(LED8,0);flag_L2=1;}
}
}
题目要求:
通过 LCD 显示当前 EEPROM 中存储的脉宽调制信号占空比、系统时间、当前正在输出
的通道以及通过串口接收到的命令,LCD 显示界面参考示意图如图 2、图 3 所示:
显示函数:
void window1()
{
u8 str1[20],str2[20],str3[20],str4[20],str5[20];
LCD_ClearLine(Line1);
sprintf(str1," PWM-PA1: %d%%",(int)(A1_pwm+1)/9);
LCD_DisplayStringLine(Line1,str1);
LCD_ClearLine(Line2);
sprintf(str2," PWM-PA2: %d%%",(int)(A2_pwm+1)/9);
LCD_DisplayStringLine(Line2,str2);
LCD_ClearLine(Line4);
sprintf(str3," Time: %0.2d: %0.2d: %0.2d",time/3600,(time%3600)/60,(time%3600)%60);
LCD_DisplayStringLine(Line4,str3);
LCD_ClearLine(Line5);
if(K1==1&&K3==1)
{
sprintf(str4," Channel: PA1 & PA2");
}
else if(K1==1)
{
sprintf(str4," Channel: PA1");
}
else if(K3==1)
{
sprintf(str4," Channel: PA2");
}
else
{
sprintf(str4," Channel: ");
}
LCD_DisplayStringLine(Line5,str4);
LCD_DisplayStringLine(Line7," Command: ");
LCD_ClearLine(Line8);
if(command==1)
{
sprintf(str5," %s",usart_str);
}
else
{
sprintf(str5," None ");
}
LCD_DisplayStringLine(Line8,str5);
}
E2PROM的写和读,包括读写16位的数据:
void x24c02_write(u8 address,u8 data)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CSendByte(data);
I2CWaitAck();
I2CStop();
}
u8 x24c02_read(u8 address)
{
u8 data;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
data=I2CReceiveByte();
I2CSendAck();
I2CStop();
return data;
}
u16 x24c02_write_u16(u8 address,u16 data)
{
union con a;
a.i=data;
x24c02_write(address,a.c[0]);
delay_ms(2);
address++;
x24c02_write(address,a.c[1]);
delay_ms(2);
}
u16 x24c02_read_u16(u8 address)
{
union con a;
a.c[0]=x24c02_read(address);
delay_ms(2);
address++;
a.c[1]=x24c02_read(address);
return a.i;
}
题目要求:
通道 PA1 输出脉宽调制信号时,指示灯 LD1 点亮,其余指示灯处于熄灭状态;
通道 PA2 输出脉宽调制信号时,指示灯 LD2 点亮,其余指示灯处于熄灭状态。
在主函数中循环判断点灯:
LED_Control(LEDALL,0);
if(K1==0)
{
LED_Control(LED1,0);
}
else
{
LED_Control(LED1,1);
}
if(K3==0)
{
LED_Control(LED2,0);
}
else
{
LED_Control(LED2,1);
}
题目要求:
系统初始化时间设定为 23 时 59 分 50 秒,PA1、PA2 输出频率固定为 1KHz,串口通讯
波特率设定为 9600 bps。
系统时钟用RTC,PA1,PA2输出频率初始为零,设置变量可调,在按键中可改变频率
RTC:
void RTC_Init()
{
/* Enable PWR and BKP clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
/* Allow access to BKP Domain */
PWR_BackupAccessCmd(ENABLE);
/* Reset Backup Domain */
BKP_DeInit();
/* Enable the LSI OSC */
RCC_LSICmd(ENABLE);
/* Wait till LSI is ready */
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
{}
/* Select the RTC Clock Source */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
/* Enable RTC Clock */
RCC_RTCCLKCmd(ENABLE);
/* Wait for RTC registers synchronization */
RTC_WaitForSynchro();
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
/* Enable the RTC Second */
RTC_ITConfig(RTC_IT_SEC, ENABLE);
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
/* Set RTC prescaler: set RTC period to 1sec */
RTC_SetPrescaler(40000);
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
RTC_SetCounter(23*3600+59*60+50);
}
void RTC_IRQHandler(void)
{
if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
{
RTC_ClearITPendingBit(RTC_FLAG_SEC);
if(RTC_GetCounter()>=86400)
{
RTC_SetCounter(0);
}
}
两路PWM初始化:
void PWM_Init(u16 arr, u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler = psc;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
TIM_Cmd(TIM2, ENABLE);
//TIM_CtrlPWMOutputs(TIM2, ENABLE);
//TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
}