(本篇博客有很多还没讲解很细致,先贴出代码,等有时间再进行注解)
“双路输出控制器”具有信号输出时间设定、输出信号占空比调整、当前输出通道及时间显示、系统工作参数存储、串口通讯及 LED 指示等功能。“双路输出控制器”通过串口完成信号输出时间设定功能;通过 EEPROM 完成系统工作参数存储功能;通过按键完成输出通道切换、输出信号占空比调整及停止信号输出功能;系统硬件电路主要由 MCU 控制单元、独立按键、LCD 显示单元、串口通讯单元、EEPROM 数据存储单元和 LED 指示单元组成,系统框图如图 1 所示:
设计任务及要求
1. 独立按键功能
1.1 按下 B1 按键,PA1 输出脉宽调制信号,再次按下 B1,PA1 持续输出低电平,如此循环;
1.2 B2 按键功能设定为通道 PA1 输出脉宽调制信号占空比调整,按下 B2,通道 PA1 输出信号占空比以 10%步进,调整后的输出信号占空比将保存至 EEPROM 中;
1.3 按下 B3 按键,PA2 输出脉宽调制信号,再次按下 B3,PA2 持续输出低电平,如此循环;
1.4 B4 按键功能设定为通道 PA2 输出脉宽调制信号占空比调整,按下 B4,通道 PA2 输出信号占空比以 10%步进,调整后的输出信号占空比将保存至 EEPROM 中。
2. 串口通讯单元
系统可通过串口接收命令,用户输入字符串“hh:mm:ss-PAx-yS”,设定 PAx 通道在 hh时 mm 分 ss 秒输出脉宽调制信号,持 续输出 y 秒(0 [命令格式举例] - 通过串口输入“00:00:20-PA1-5S”,即设定系统在 0 时 0 分 20 秒通过 3. LCD 显示单元 通过 LCD 显示当前 EEPROM 中存储的脉宽调制信号占空比、系统时间、当前正在输出的通道以及通过串口接收到的命令,LCD 显示界面参考示意图如图 2、图 3 所示: 4. EEPROM 数据存储单元 通过 EEPROM 存储 PA1、PA2 输出信号的占空比,占空比数值可以通过按键调整。 5. LED 指示功能 6. 系统工作及初始化状态说明 系统初始化时间设定为 23 时 59 分 50 秒,PA1、PA2 输出频率固定为 1KHz,串口通讯波特率设定为 9600 bps。
PA1 通道持续输出脉宽调制信号,5 秒后输出低电平信号。
通道 PA1 输出脉宽调制信号时,指示灯 LD1 点亮,其余指示灯处于熄灭状态;
通道 PA2 输出脉宽调制信号时,指示灯 LD2 点亮,其余指示灯处于熄灭状态。二、模块化代码分析
1、初始化部分
#include "stm32f10x.h"
#include "lcd.h"
#include "stdio.h"
#include "i2c.h"
#include "IO.h"
u32 TimingDelay = 0;
u8 RXCUNT = 0;
u8 RXOVER = 0;
u8 RXBUF[20];
u8 i;
u8 key_Flag = 0;
u8 string[20];
u8 RTC_Read = 0;
u32 TimeVal;
u8 hour,min,sec;
u8 RX_hour,RX_min,RX_sec,RX_ch,RX_delay;
u8 LED_Flag = 0;
u8 A1_Duty = 10,A2_Duty = 10;
extern u8 CH2_OutPut,CH3_OutPut;
extern u16 LED_MODE;
void Delay_Ms(u32 nTime);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
SysTick_Config(SystemCoreClock/1000);
i2c_init();
USART2_Init(9600);
LED_Init();
KEY_Init();
RTC_Init(23,59,55);
A1_Duty = _24c02_read(0xaa);
A2_Duty = _24c02_read(0xbb);
TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,1,0,0);
LCD_DisplayStringLine(Line9, "None");
LCD_DisplayStringLine(Line8, " Command : ");
2、串口部分
if(RXOVER == 1)
{
//USART2_SendString(RXBUF);
RX_hour =(RXBUF[0] - 0x30) * 10 + (RXBUF[1] - 0x30);
RX_min = (RXBUF[3] - 0x30) * 10 + (RXBUF[4] - 0x30);
RX_sec = (RXBUF[6] - 0x30) * 10 + (RXBUF[7] - 0x30);
RX_ch = RXBUF[11] - 0x30;
LCD_ClearLine(Line9);
LCD_DisplayStringLine(Line9, RXBUF);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
RXOVER = 0;
}
3、按键部分
if(key_Flag == 1) // 50ms
{
KEY_Read();
key_Flag = 0;
}
void KEY_Read(void)
{
static u16 key1_sum = 0,key2_sum = 0,key3_sum = 0,key4_sum = 0;
if(KEY1 == 0)
{
key1_sum++;
if(key1_sum == 1)
{
CH2_OutPut ^= 1;
TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,0,CH2_OutPut,CH3_OutPut);
}
}else
{
key1_sum = 0;
}
if(KEY2 == 0)
{
key2_sum++;
if(key2_sum == 1)
{
A1_Duty += 10;
if(A1_Duty == 100)
{
A1_Duty = 10;
}
_24c02_write(0xaa,A1_Duty);
TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,0,CH2_OutPut,CH3_OutPut);
}
}else
{
key2_sum = 0;
}
if(KEY3 == 0)
{
key3_sum++;
if(key3_sum == 1)
{
CH3_OutPut ^= 1;
TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,0,CH2_OutPut,CH3_OutPut);
}
}else
{
key3_sum = 0;
}
if(KEY4 == 0)
{
key4_sum++;
if(key4_sum == 1)
{
A2_Duty += 10;
if(A2_Duty == 100)
{
A2_Duty = 10;
}
_24c02_write(0xbb,A1_Duty);
TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,0,CH2_OutPut,CH3_OutPut);
}
}else
{
key4_sum = 0;
}
}
4、RTC部分
if(RTC_Read == 1)
{
TimeVal = RTC_GetCounter();
hour = TimeVal / 3600;
min = TimeVal % 3600 / 60;
sec = TimeVal % 3600 % 60;
if(TimeVal == (RX_hour * 3600 + RX_min * 60 + RX_sec))
{
RX_delay = RXBUF[13] - 0x30;
if(RX_ch == 1)
{
CH2_OutPut = 1;
}
if(RX_ch == 2)
{
CH3_OutPut = 1;
}
TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,0,CH2_OutPut,CH3_OutPut);
}
if(!RX_delay)
{
if(RX_ch == 1)
{
CH2_OutPut = 0;
}
if(RX_ch == 2)
{
CH3_OutPut = 0;
}
TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,0,CH2_OutPut,CH3_OutPut);
for(i = 0;i < 20;i++)
{
RXBUF[i] = 0;
}
}
RTC_Read = 0;
}
5、LED部分
if(LED_Flag)
{
if(CH2_OutPut)
{
LED_MODE &= ~(1<<8);
GPIOC->ODR = LED_MODE;
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}else
{
LED_MODE |= (1<<8);
GPIOC->ODR = LED_MODE;
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}
if(CH3_OutPut)
{
LED_MODE &= ~(1<<9);
GPIOC->ODR = LED_MODE;
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}else
{
LED_MODE |= (1<<9);
GPIOC->ODR = LED_MODE;
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}
}
6、LCD显示
sprintf((char *)string," PWM-PA1 : %d %% ",A1_Duty);
LCD_DisplayStringLine(Line1, string);
sprintf((char *)string," PWM-PA2 : %d %% ",A2_Duty);
LCD_DisplayStringLine(Line3, string);
sprintf((char *)string," TIME : %.2d:%.2d:%.2d ",hour,min,sec);
LCD_DisplayStringLine(Line5, string);
if(CH2_OutPut && CH3_OutPut)
{
sprintf((char *)string," Channel : PA1 PA2 ");
LCD_DisplayStringLine(Line6, string);
}else
if(CH2_OutPut)
{
sprintf((char *)string," Channel : PA1 ");
LCD_DisplayStringLine(Line6, string);
}else
if(CH3_OutPut)
{
sprintf((char *)string," Channel : PA2 ");
LCD_DisplayStringLine(Line6, string);
}else
{
sprintf((char *)string," Channel : ");
LCD_DisplayStringLine(Line6, string);
}
7、滴答定时器及中断部分
void USART2_IRQHandler(void)
{
u8 temp;
if(USART_GetITStatus(USART2,USART_IT_RXNE) == 1)
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
temp = USART_ReceiveData(USART2);
if(temp == '\n')
{
RXCUNT = 0;
RXOVER = 1;
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
}else
{
RXBUF[RXCUNT] = temp;
RXCUNT++;
}
}
}
void RTC_IRQHandler(void)
{
while(RTC_GetITStatus(RTC_IT_SEC) == 1)
{
RTC_ClearITPendingBit(RTC_IT_SEC);
RTC_Read = 1;
if(RTC_GetCounter() == (24 * 3600))
{
RTC_SetCounter(0x0);
RTC_WaitForLastTask();
}
}
}
void SysTick_Handler(void)
{
static u8 key_sum = 0;
static u16 second_sum = 0;
static u8 LED_sum = 0;
TimingDelay--;
if(++key_sum == 50) //50ms
{
key_sum = 0;
key_Flag = 1;
}
if(++second_sum == 1000) //1s
{
second_sum = 0;
if(RX_delay) RX_delay--;
}
if(++LED_sum == 200) // 200ms
{
LED_sum = 0;
LED_Flag = 1;
}
}
三、通用初始化部分
#include "IO.h"
u16 LED_MODE = 0XFFFF;
extern u8 A1_Duty,A2_Duty;
u8 CH2_OutPut = 0,CH3_OutPut = 0;
/////////////// 24c02 /////////////////////////
void _24c02_write(u8 address,u8 data)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CSendByte(data);
I2CWaitAck();
I2CStop();
}
u8 _24c02_read(u8 address)
{
u8 temp;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
temp = I2CReceiveByte();
return temp;
}
void USART2_Init(u32 bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_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_Mode = USART_Mode_Rx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART2,&USART_InitStructure);
USART_Cmd(USART2, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}
//void USART2_SendString(u8 *str)
//{
// u8 index = 0;
// do
// {
// USART_SendData(USART2, str[index]);
// while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == 0);
// index++;
// }while(str[index] != 0);
//}
/////////////////////// LED /////////////////////////////
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = 0XFF00;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIOC->ODR = 0XFFFF;
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
///////////////// RTC //////////////////////////////
void RTC_Init(u8 HH,u8 MM,u8 SS)
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
RCC_LSICmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_SetPrescaler(40000-1);
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
RTC_SetCounter(HH * 3600 + MM * 60 + SS);
RTC_WaitForLastTask();
}
///////////////// PWM /////////////////////////////
void TIM2_PA1_PWM_Init(u8 duty_A1,u8 duty_A2,u8 status,u8 CH2_OPEN,u8 CH3_OPEN)
{
u32 A1_Pluse,A2_Pluse;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
if(status)
{
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_TimeBaseInitStructure.TIM_Period = 999;
TIM_TimeBaseInitStructure.TIM_Prescaler = 71;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
}
A1_Pluse = 998 * duty_A1 / 100;
A2_Pluse = 998 * duty_A2 / 100;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
if(CH2_OPEN)
{
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
}else
{
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
}
TIM_OCInitStructure.TIM_Pulse = A1_Pluse;
TIM_OC2Init(TIM2,&TIM_OCInitStructure);
if(CH3_OPEN)
{
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
}else
{
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
}
TIM_OCInitStructure.TIM_Pulse = A2_Pluse;
TIM_OC3Init(TIM2,&TIM_OCInitStructure);
if(status)
{
TIM_Cmd(TIM2,ENABLE);
}
}