/** * Automatically called by @ref gprot_register_changed() * * Implements the logic associated with the application specific flag register. */ void gprot_update_flags(void) { if ((gprot_flag_reg & GPROT_FLAG_PWM_COMM) != 0) { pwm_comm(); return; } if ((gprot_flag_reg & GPROT_FLAG_COMM_TIM) != 0) { if ((gprot_flag_reg_old & GPROT_FLAG_COMM_TIM) == 0) { control_process_ignite(); } } else { if ((gprot_flag_reg_old & GPROT_FLAG_COMM_TIM) != 0) { control_process_kill(); } } if ((gprot_flag_reg & GPROT_FLAG_ADC_COMM) != 0) { demo = true; } else { if ((gprot_flag_reg_old & GPROT_FLAG_ADC_COMM) != 0) { demo = false; } } if ((gprot_flag_reg & GPROT_FLAG_ALL_LO) != 0) { pwm_all_lo(); } else { if ((gprot_flag_reg_old & GPROT_FLAG_ALL_LO) != 0) { pwm_off(); } } if ((gprot_flag_reg & GPROT_FLAG_ALL_HI) != 0) { pwm_all_hi(); } else { if ((gprot_flag_reg_old & GPROT_FLAG_ALL_HI) != 0) { pwm_off(); } } /* add other flags here (up to 16) */ gprot_flag_reg_old = gprot_flag_reg; }
/** * Initialize the three phase (6outputs) PWM peripheral and internal state. */ void pwm_init(void) { NVIC_InitTypeDef nvic; GPIO_InitTypeDef gpio; TIM_TimeBaseInitTypeDef tim_base; TIM_OCInitTypeDef tim_oc; TIM_BDTRInitTypeDef tim_bdtr; (void)gpc_setup_reg(GPROT_PWM_OFFSET_REG_ADDR, &pwm_offset); /* Enable clock for TIM1 subsystem */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); /* Enable TIM1 interrupt */ nvic.NVIC_IRQChannel = TIM1_TRG_COM_IRQn; nvic.NVIC_IRQChannelPreemptionPriority = 0; nvic.NVIC_IRQChannelSubPriority = 1; nvic.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&nvic); /* Enable TIM1 interrupt */ nvic.NVIC_IRQChannel = TIM1_CC_IRQn; nvic.NVIC_IRQChannelPreemptionPriority = 0; nvic.NVIC_IRQChannelSubPriority = 1; nvic.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&nvic); /* GPIOA: TIM1 channel 1, 2 and 3 as alternate function push-pull */ gpio.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10; gpio.GPIO_Mode = GPIO_Mode_AF_PP; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &gpio); /* GPIOB: TIM1 channel 1N, 2N and 3N as alternate function * push-pull */ gpio.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_Init(GPIOB, &gpio); /* Time base configuration */ tim_base.TIM_Period = PWM__BASE_CLOCK / PWM__FREQUENCY; tim_base.TIM_Prescaler = 0; tim_base.TIM_ClockDivision = 0; tim_base.TIM_CounterMode = TIM_CounterMode_Up; tim_base.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM1, &tim_base); /* TIM1 channel 1, 2 and 3 settings */ tim_oc.TIM_OCMode = TIM_OCMode_Timing; tim_oc.TIM_OutputState = TIM_OutputState_Enable; tim_oc.TIM_OutputNState = TIM_OutputNState_Enable; tim_oc.TIM_Pulse = pwm_val; tim_oc.TIM_OCPolarity = TIM_OCPolarity_High; tim_oc.TIM_OCNPolarity = TIM_OCNPolarity_High; tim_oc.TIM_OCIdleState = TIM_OCIdleState_Set; tim_oc.TIM_OCNIdleState = TIM_OCNIdleState_Set; TIM_OC1Init(TIM1, &tim_oc); TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); TIM_OC2Init(TIM1, &tim_oc); TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable); TIM_OC3Init(TIM1, &tim_oc); TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable); /* TIM1 configure channel 4 as adc trigger source */ tim_oc.TIM_OCMode = TIM_OCMode_PWM2; tim_oc.TIM_Pulse = pwm_offset; TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable); TIM_OC4Init(TIM1, &tim_oc); /* Automatic Output enable, break, dead time and lock configuration */ tim_bdtr.TIM_OSSRState = TIM_OSSRState_Enable; tim_bdtr.TIM_OSSIState = TIM_OSSIState_Enable; tim_bdtr.TIM_LOCKLevel = TIM_LOCKLevel_OFF; tim_bdtr.TIM_DeadTime = 10; tim_bdtr.TIM_Break = TIM_Break_Disable; tim_bdtr.TIM_BreakPolarity = TIM_BreakPolarity_High; tim_bdtr.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable; TIM_BDTRConfig(TIM1, &tim_bdtr); TIM_CCPreloadControl(TIM1, ENABLE); /* Enable COM and CC interrupt */ TIM_ITConfig(TIM1, TIM_IT_COM, ENABLE); //TIM_ITConfig(TIM1, TIM_IT_COM | TIM_IT_CC4, ENABLE); /* TIM1 enable counter */ TIM_Cmd(TIM1, ENABLE); /* Main output enable */ TIM_CtrlPWMOutputs(TIM1, ENABLE); /* Setting default state of pwm to pwm_off */ pwm_off(); }
int main(void) { char key; // Map the I/O sections setup_io(); // Set ALL GPIO pins to the required mode setup_gpio(); // Set up PWM module setup_pwm(); // Setup the SPI setup_spi(); // We don't touch the UART for now // // Here your main program can start // do { printf(" l/L : Walk the LEDS\n"); printf(" b/B : Show buttons\n"); printf(" m/M : Control the motor\n"); printf(" a/A : Read the ADC values\n"); printf(" c/C : ADC => Motor\n"); printf("( D : Set the DAC values\n"); printf(" q/Q : Quit program\n"); key = getchar(); switch (key) { case 'l': case 'L': quick_led_demo(); break; case 'b': case 'B': quick_buttons_demo(); break; case 'm': case 'M': quick_pwm_demo(); break; case 'a': case 'A': quick_adc_demo(); break; case 'c': case 'C': adc_pwm_demo(); break; case 0x0A: case 0x0D: // ignore CR/LF break; default: printf("???\n"); } } while (key!='q' && key!='Q'); // make sure everything is off! leds_off(); pwm_off(); restore_io(); return 0; } // main
/********************************** 函数实现区 *********************************/ void pwm_init(void) { uint32_T pre_scale_val = 0; /* * * 将计数器时钟设置为:15MHz, 计算预分频值 * PWM_TIMCLK使用 APB1 的时钟 即 HCLK/2 * * 预分频值: * pre_scale_val = (APB1_CLK / PWM_TIM_CLK ) - 1 * => pre_scale_val = ((SystemCoreClock / 2 ) /15 MHz) - 1 * */ pre_scale_val = (uint32_t)((SystemCoreClock/2) / 15000000) - 1; /* * 设置周期为:1000 便于编程 * ARR = (PWM_TIM源时钟/PWM_TIM输出频率) - 1 * => PWM_TIM输出频率 = PWM_TIM源时钟 / (ARR + 1) * ARR = 1000 * PWM_TIM源时钟:15MHz * => PWM_TIM输出频率 = 15000000 / (1000 + 1) * = 14.985 kHz * * 设置PWM_TIM输出频率为20 KHz, 周期(ARR)为: * ARR = (PWM_TIM源时钟/PWM_TIM输出频率) - 1 * = 749 * */ s_period = 1000; /* 配置PWM_TIM计数器: * Initialize PWM_TIM peripheral as follows: * Prescaler = (SystemCoreClock / 2 / 15000000) - 1 * Period = (750 - 1) * ClockDivision = 0 * Counter direction = Up * */ s_tim_handle.Instance = PWM_TIM; s_tim_handle.Init.Prescaler = pre_scale_val; s_tim_handle.Init.Period = s_period; s_tim_handle.Init.ClockDivision = 0; s_tim_handle.Init.CounterMode = TIM_COUNTERMODE_UP; s_tim_handle.Init.RepetitionCounter = 0; if (HAL_TIM_PWM_Init(&s_tim_handle) != HAL_OK) { ERR_STR("执行失败."); } /* 各通道的占空比计算如下: * PWM_TIM_Channel1 占空比 = (PWM_TIM_CCR1/ PWM_TIM_ARR + 1)* 100 * PWM_TIM Channel2 占空比 = (PWM_TIM_CCR2/ PWM_TIM_ARR + 1)* 100 * PWM_TIM Channel3 占空比 = (PWM_TIM_CCR3/ PWM_TIM_ARR + 1)* 100 * PWM_TIM Channel4 占空比 = (PWM_TIM_CCR4/ PWM_TIM_ARR + 1)* 100 * * 初始化的时候占空比全0 */ /* 所有通道都需要 */ s_sConfig.OCMode = TIM_OCMODE_PWM1; s_sConfig.OCPolarity = TIM_OCPOLARITY_HIGH; s_sConfig.OCFastMode = TIM_OCFAST_DISABLE; s_sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH; s_sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET; s_sConfig.OCIdleState = TIM_OCIDLESTATE_RESET; /* 测试电机 */ pwm_test(); /* 关闭电机 */ pwm_off(); return; }
/** * @brief Handles the given user command * * This handles the given user command (user_command_t) either by processing * it directly, or by passing it over to the actual handler using * UserState_HandleUserCommand(). * * g_eepromSaveDelay and g_checkIfAutoOffDelay get reset every time this * function is called to make sure the appropriate functionality works as * intended. * * @param user_command The user command that should be handled * * @see UserState_HandleUserCommand() * @see g_eepromSaveDelay * @see g_checkIfAutoOffDelay */ void handle_user_command(user_command_t user_command) { if (UC_ONOFF == user_command) { log_state("OF\n"); if (user_power_state < UPS_AUTO_OFF) { user_power_state = UPS_MANUAL_OFF; pwm_off(); } else { if (user_power_state == UPS_MANUAL_OFF) { user_power_state = UPS_NORMAL_ON; } else { user_power_state = UPS_OVERRIDE_ON; } pwm_on(); user_setNewTime(NULL); } preferences_save(); } else { int8_t i; bool handled = false; for (i = g_topOfStack - 1; i >= 0 && !handled; --i) { handled |= UserState_HandleUserCommand(g_stateStack[i], user_command); } if (!handled) { if (UC_BRIGHTNESS_UP == user_command) { log_state("B+\n"); pwm_increase_brightness(); } else if (UC_BRIGHTNESS_DOWN == user_command) { log_state("B-\n"); pwm_decrease_brightness(); } else if (UC_NORMAL_MODE == user_command) { addSubState(-1, MS_normalMode, (void*)1); } else if (UC_SET_TIME == user_command) { addState(MS_setSystemTime, NULL); } else if (UC_SET_ONOFF_TIMES == user_command) { addState(MS_setOnOffTime, NULL); } else if (UC_DEMO_MODE == user_command) { menu_state_t curTop = user_get_current_menu_state(); log_state("BS\n"); if (MS_demoMode == curTop) { quitMyself(MS_demoMode, NULL); } else { addState(MS_demoMode, NULL); } } else if (UC_CALIB_BRIGHTNESS == user_command) { pwm_modifyLdrBrightness2pwmStep(); // Indicate the change to user if (pwm_is_enabled()) { pwm_off(); _delay_ms(USER_VISUAL_INDICATION_TOGGLE_MS); pwm_on(); } } else if (UC_PULSE_MODE == user_command) { menu_state_t curTop = user_get_current_menu_state(); log_state("PLS\n"); if (MS_pulse == curTop) { leaveSubState(g_topOfStack - 1); } else { if ((MS_normalMode == curTop) #if (ENABLE_RGB_SUPPORT == 1) || (MS_hueMode == curTop) #endif ) { addState(MS_pulse, NULL); } } DISPLAY_SPECIAL_USER_COMMANDS_HANDLER #if (ENABLE_RGB_SUPPORT == 1) } else if (UC_HUE_MODE == user_command) { log_state("HM"); addSubState(-1, MS_hueMode, NULL); #endif #if (ENABLE_DCF_SUPPORT == 1) } else if (UC_DCF_GET_TIME == user_command) { log_state("DCF\n"); dcf77_enable(); #endif #if (ENABLE_AMBILIGHT_SUPPORT == 1) } else if (UC_AMBILIGHT == user_command) { log_state("AL\n"); PIN(USER_AMBILIGHT) |= _BV(BIT(USER_AMBILIGHT)); #endif #if (ENABLE_BLUETOOTH_SUPPORT == 1) } else if (UC_BLUETOOTH == user_command) { log_state("BT\n"); PIN(USER_BLUETOOTH) |= _BV(BIT(USER_BLUETOOTH)); #endif #if (ENABLE_AUXPOWER_SUPPORT == 1) } else if (UC_AUXPOWER == user_command) { log_state("AUX\n"); PIN(USER_AUXPOWER) |= _BV(BIT(USER_AUXPOWER)); #endif } else { return; } }