This post was last edited by Qintianqintian0303 on 2022-8-10 20:59
02Clock Configuration + LED Operation
Preface
In the above text, we selected the corresponding development project. Now we will carry out our software development in AT32WB415_Firmware_Library_V2.0.2\project\at_start_wb415\templates\iar_v8.2.
Target
Be familiar with the chip clock configuration and LED operation. This time, you will change the LED display mode by pressing buttons.
accomplish
The configuration of the chip clock mainly relies on the selection of various clock configurations in the clock tree, which is intuitive and efficient:
This software project is currently the routine that comes with the development board. Regarding the clock configuration, in fact, EXTERN SystemInit in the header file is the clock configuration that is executed. The SystemInit in system_at32wb415.c is as follows:
It is a direct register initial assignment, which is not suitable for us to modify directly. It is not easy to understand and prone to errors. Therefore, Arteli has performed a clock configuration in main system_clock_config(); You can modify the register configuration inside. AT32WB415CCU7-7 does not consider power consumption at present. Due to the existence of USB, it must be able to obtain 48M through PLLCLK division, so PLLCLK can be designed to be 144 at most under the limit of 150M. HEXT obtains PLLCLK after 18 times.
Next, we will design the operation of LED. First, we will plan the LED mode. One is to turn all LEDs on and off, the second is to light up the LEDs in a cycle, both of which are basic IO operations; the third is to light up the LEDs in a cycle, which mainly involves the timed PWM output function. The mode switching is done by key operation, which involves external interrupt operation, and the anti-shake operation is done in the timer.
The following is the specific configuration:
Initialization of LED corresponding IO port:
void LED_GPIO_init(void)
{
gpio_init_type gpio_init_struct;
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);/* enable the led clock */
gpio_default_para_init(&gpio_init_struct);/* set default parameter */
/* configure the led gpio */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_7|GPIO_PINS_8|GPIO_PINS_9;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
}
Perform IO port operation macro definition:
/************************************宏定义************************************/
#define LEDRed_on gpio_bits_reset(GPIOB,GPIO_PINS_7);
#define LEDRed_off gpio_bits_set(GPIOB,GPIO_PINS_7);
#define LEDRed_Toggle gpio_bits_TogglePin(GPIOB,GPIO_PINS_7);
#define LEDYellow_on gpio_bits_reset(GPIOB,GPIO_PINS_8);
#define LEDYellow_off gpio_bits_set(GPIOB,GPIO_PINS_8);
#define LEDYellow_Toggle gpio_bits_TogglePin(GPIOB,GPIO_PINS_8);
#define LEDGreen_on gpio_bits_reset(GPIOB,GPIO_PINS_9);
#define LEDGreen_off gpio_bits_set(GPIOB,GPIO_PINS_9);
#define LEDGreen_Toggle gpio_bits_TogglePin(GPIOB,GPIO_PINS_9);
Note: Lights up when IO is low
Assign initial value to IO port:
void LED_init(void)
{
LEDRed_on;
LEDYellow_on;
LEDGreen_on;
}
The following is the basic timer configuration:
void Tmr10Base_init(uint16_t Period)
{
/* enable tmr10 clock */
crm_periph_clock_enable(CRM_TMR10_PERIPH_CLOCK, TRUE);
/* tmr1 configuration */
/* time base configuration */
/* systemclock/14400/10000 = 1hz */
tmr_base_init(TMR10, Period * 10 - 1, 14400 - 1);
tmr_cnt_dir_set(TMR10, TMR_COUNT_UP);
/* overflow interrupt enable */
tmr_interrupt_enable(TMR10, TMR_OVF_INT, TRUE);
/* tmr10 overflow interrupt nvic init */
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 0, 2);
/* enable tmr10 */
tmr_counter_enable(TMR10, TRUE);
}
The basic timer is timer 10. Pay attention to the calculation of frequency division. Period corresponds to the timing in ms.
To configure external interrupts:
void port_EXIT_init(void)
{
exint_init_type exint_init_struct;
crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE0);
exint_default_para_init(&exint_init_struct);
exint_init_struct.line_enable = TRUE;
exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
exint_init_struct.line_select = EXINT_LINE_0;
exint_init_struct.line_polarity = EXINT_TRIGGER_RISING_EDGE;
exint_init(&exint_init_struct);
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
nvic_irq_enable(EXINT0_IRQn, 1, 0);
}
The key press is judged by external interrupt + timer, and a structure is defined for this purpose.
typedef struct
{
uint8_t EXIT_flag; //中断触发标志
uint8_t EXIT_Data; //中断触发防抖计时
uint8_t Press_flag; //按键触发标志
uint8_t Press_Data; //按键类型判断计时
uint8_t ShortPress_flag; //短按触发标志
uint8_t LongPress_flag; //长按触发标志
}key;
extern key key_Ok;
In the external interrupt, only EXIT_flag is set, and the most important thing is to perform anti-shake and key recognition through the timer;
if(key_Ok.EXIT_flag == 1)//防抖判断
{
key_Ok.EXIT_Data++;
if(key_Ok.EXIT_Data == 2 && READ_KEY_OK == 1)
{
key_Ok.Press_flag = 1;
key_Ok.Press_Data = 0;
key_Ok.ShortPress_flag = 0;
key_Ok.LongPress_flag = 0;
key_Ok.EXIT_flag = 0;
}
else if(key_Ok.EXIT_Data > 2)
{
key_Ok.EXIT_flag = 0;
key_Ok.EXIT_Data = 0;
}
}
if(key_Ok.Press_flag == 1)
{
key_Ok.Press_Data++;
if(READ_KEY_OK == 0)
{
if(key_Ok.Press_Data >= 100)
{
key_Ok.LongPress_flag = 1;
}
else if(key_Ok.Press_Data < 100)
{
key_Ok.ShortPress_flag = 1;
}
key_Ok.Press_flag = 0;
}
else
{
if(key_Ok.Press_Data >= 120)
{
key_Ok.LongPress_flag = 1;
key_Ok.Press_flag = 0;
}
}
}
Judging from the schematic diagram and data sheet, the PWM output corresponds to channels 2, 3, and 4 of TIM4, and the configuration is as follows:
if(key_Ok.EXIT_flag == 1)//防抖判断
{
key_Ok.EXIT_Data++;
if(key_Ok.EXIT_Data == 2 && READ_KEY_OK == 1)
{
key_Ok.Press_flag = 1;
key_Ok.Press_Data = 0;
key_Ok.ShortPress_flag = 0;
key_Ok.LongPress_flag = 0;
key_Ok.EXIT_flag = 0;
}
else if(key_Ok.EXIT_Data > 2)
{
key_Ok.EXIT_flag = 0;
key_Ok.EXIT_Data = 0;
}
}
if(key_Ok.Press_flag == 1)
{
key_Ok.Press_Data++;
if(READ_KEY_OK == 0)
{
if(key_Ok.Press_Data >= 100)
{
key_Ok.LongPress_flag = 1;
}
else if(key_Ok.Press_Data < 100)
{
key_Ok.ShortPress_flag = 1;
}
key_Ok.Press_flag = 0;
}
else
{
if(key_Ok.Press_Data >= 120)
{
key_Ok.LongPress_flag = 1;
key_Ok.Press_flag = 0;
}
}
}
The following sets the frequency of the breathing light to 2s and defines the LED control structure:
typedef struct
{
uint8_t Mode_Dis; //LED显示模式
uint8_t Mode_OidDis; //LED上一次显示模式
uint8_t PWMcnt; //PWM控制
uint8_t state; //LED过程
uint8_t UpFlag; //更新标志
uint8_t Upcnt; //更新计时
}LED_states;
extern LED_states LED;
void App_LED(void)
{
if(LED.Mode_OidDis != LED.Mode_Dis)
{
LED.Upcnt = 0;
LED.state = 0;
LED.UpFlag = 1;
if(LED.Mode_OidDis == 2)
{
tmr_counter_enable(TMR4, FALSE);
LED_GPIO_init();
}
else
{
LEDRed_off;
LEDYellow_off;
LEDGreen_off;
}
switch(LED.Mode_Dis)
{
case 0:
LEDRed_on;
LEDYellow_on;
LEDGreen_on;
break;
case 1:
LEDRed_on;
break;
case 2:
Tmr4PWM_init(Tmr4PWM);
LED.Upcnt = 0;
break;
default:
break;
}
LED.Mode_OidDis = LED.Mode_Dis;
}
if(LED.UpFlag == 1)
{
if(LED.Mode_Dis == 0)
{
LEDRed_Toggle;
LEDYellow_Toggle;
LEDGreen_Toggle;
}
else if(LED.Mode_Dis == 1)
{
switch(LED.state)
{
case 0:
LEDRed_on;
LEDGreen_off;
break;
case 1:
LEDRed_Toggle;
LEDYellow_Toggle;
break;
case 2:
LEDYellow_Toggle;
LEDGreen_Toggle;
break;
default:
break;
}
}
else if(LED.Mode_Dis == 2)
{
switch(LED.state)
{
case 0:
tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_2, LED.PWMcnt*50);
break;
case 1:
tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_3, LED.PWMcnt*50);
break;
case 2:
tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_4, LED.PWMcnt*50);
break;
default:
break;
}
}
LED.UpFlag = 0;
}
}
There are many forms of LED operation. Here are three representative ones. You can also use your imagination to achieve different aesthetic expressions.
The video is as follows:
点击上图查看Gif动图