前言
该系列采用Arm® Cortex®-M4内核,处理器主频高达240MHz,可支持算法复杂度更高的嵌入式应用,并具备更快速的实时处理能力。
GD32F4新产品配备了512KB到3072KB片上Flash,代码执行零等待区提升至1024KB。还配备了256KB到768KB的SRAM,以业界领先的大容量存储优势支持高级计算、通信网络、人机界面等工业及消费类多元化应用场景。
回到正题,本次开发设计的试验为:油液颗粒检测仪系统(简单版),能够实现OLED显示、舵机控制、ADC电压显示、串口等功能。
效果图
系统框架
软件设计
1.OLED显示
使用SPI,1.3寸OLED显示。
extern unsigned char BMP1[];
void OLED_display_info()
{
OLED_ShowCHinese(10,0,9,16,1);
OLED_ShowCHinese(28,0,10,16,1);
OLED_ShowCHinese(46,0,58,16,1);
OLED_ShowCHinese(64,0,59,16,1);
OLED_ShowCHinese(82,0,60,16,1);
OLED_ShowCHinese(100,0,61,16,1);
delay_1ms(200);
OLED_ShowCHinese(0,25,6,16,1);
OLED_ShowCHinese(18,25,7,16,1);
OLED_ShowCHinese(36,25,8,16,1);
OLED_ShowString(54,25,":",16,1);
delay_1ms(200);
OLED_ShowCHinese(0,48,9,16,1);
OLED_ShowCHinese(18,48,10,16,1);
OLED_ShowCHinese(36,48,11,16,1);
OLED_ShowString(54,48,":",16,1);
delay_1ms(200);
OLED_Refresh();
}
void my_testA0(void)
{
OLED_Clear(0);
OLED_ShowCHinese(5,16,49,16,1);
OLED_ShowCHinese(23,16,50,16,1);
OLED_ShowCHinese(41,16,51,16,1);
OLED_ShowCHinese(59,16,52,16,1);
OLED_ShowCHinese(77,16,53,16,1);
OLED_ShowCHinese(95,16,54,16,1);
OLED_ShowCHinese(113,16,55,16,1);
OLED_Refresh();
}
void my_testB1(void)
{
OLED_Clear(0);
OLED_ShowString(100,0,"<",16,1);
OLED_ShowCHinese(0,0,12,16,1);
OLED_ShowCHinese(20,0,13,16,1);
OLED_ShowCHinese(40,0,14,16,1);
OLED_ShowCHinese(60,0,15,16,1);
OLED_ShowString(0,16,"1.",16,1);
OLED_ShowCHinese(20,16,16,16,1);
OLED_ShowCHinese(40,16,17,16,1);
OLED_ShowCHinese(60,16,14,16,1);
OLED_ShowCHinese(80,16,15,16,1);
OLED_ShowString(0,32,"2.",16,1);
OLED_ShowCHinese(20,32,18,16,1);
OLED_ShowCHinese(40,32,19,16,1);
OLED_ShowCHinese(60,32,14,16,1);
OLED_ShowCHinese(80,32,15,16,1);
OLED_ShowString(0,48,"3.",16,1);
OLED_ShowCHinese(20,48,44,16,1);
OLED_ShowCHinese(40,48,45,16,1);
OLED_ShowCHinese(60,48,14,16,1);
OLED_ShowCHinese(80,48,15,16,1);
OLED_Refresh();
}
void my_testB2(void)
{
OLED_Clear(0);
OLED_ShowString(100,16,"<",16,1);
OLED_ShowCHinese(0,0,12,16,1);
OLED_ShowCHinese(20,0,13,16,1);
OLED_ShowCHinese(40,0,14,16,1);
OLED_ShowCHinese(60,0,15,16,1);
OLED_ShowString(0,16,"1.",16,1);
OLED_ShowCHinese(20,16,16,16,1);
OLED_ShowCHinese(40,16,17,16,1);
OLED_ShowCHinese(60,16,14,16,1);
OLED_ShowCHinese(80,16,15,16,1);
OLED_ShowString(0,32,"2.",16,1);
OLED_ShowCHinese(20,32,18,16,1);
OLED_ShowCHinese(40,32,19,16,1);
OLED_ShowCHinese(60,32,14,16,1);
OLED_ShowCHinese(80,32,15,16,1);
OLED_ShowString(0,48,"3.",16,1);
OLED_ShowCHinese(20,48,44,16,1);
OLED_ShowCHinese(40,48,45,16,1);
OLED_ShowCHinese(60,48,14,16,1);
OLED_ShowCHinese(80,48,15,16,1);
OLED_Refresh();
}
void my_testB3(void)
{
OLED_Clear(0);
OLED_ShowString(100,32,"<",16,1);
OLED_ShowCHinese(0,0,12,16,1);
OLED_ShowCHinese(20,0,13,16,1);
OLED_ShowCHinese(40,0,14,16,1);
OLED_ShowCHinese(60,0,15,16,1);
OLED_ShowString(0,16,"1.",16,1);
OLED_ShowCHinese(20,16,16,16,1);
OLED_ShowCHinese(40,16,17,16,1);
OLED_ShowCHinese(60,16,14,16,1);
OLED_ShowCHinese(80,16,15,16,1);
OLED_ShowString(0,32,"2.",16,1);
OLED_ShowCHinese(20,32,18,16,1);
OLED_ShowCHinese(40,32,19,16,1);
OLED_ShowCHinese(60,32,14,16,1);
OLED_ShowCHinese(80,32,15,16,1);
OLED_ShowString(0,48,"3.",16,1);
OLED_ShowCHinese(20,48,44,16,1);
OLED_ShowCHinese(40,48,45,16,1);
OLED_ShowCHinese(60,48,14,16,1);
OLED_ShowCHinese(80,48,15,16,1);
OLED_Refresh();
}
typedef struct
{
unsigned char current;
unsigned char down;
unsigned char enter;
void(*current_operation)();
}key_table;
key_table table[30]=
{
{0,0,1,(*my_testA0)},
{1,2, 1,(*my_testB1)},
{2,3, 7,(*my_testB2)},
{3,4, 8,(*my_testB3)},
{4,5, 9,(*my_testB4)},
{5,6, 10,(*my_testB5)},
{6,1, 1,(*my_testB6)},
{7,7,2,(*my_testC5)},
{8,8,3,(*my_testC6)},
{9,9,4,(*my_testC7)},
{10,11,12,(*my_testC8)},
{11,10,5,(*my_testC9)},
};
void(*current_operation_index)();
unsigned char func_index =0;
unsigned char last_index =127;
其余显示部分省略,可通过PCtoLCD2002软件,实现图片的代码转换。OLED字库使用SPI通用字库
2.按键
使用板子自带的按键,长按确定,短按为菜单调整。
#define KEY_Press 0
#define KEY_Pull 1
#define LongPressCount 80
#define KEY1Value 10
#define KEY1LongValue 11
void Scan_Keys_OLED()
{
uint8_t CountPressTime=0;
if(gpio_input_bit_get(GPIOA, GPIO_PIN_0)== RESET)
{
delay_1ms(10);
if(gpio_input_bit_get(GPIOA, GPIO_PIN_0)== RESET)
{
delay_1ms(10);
if(gpio_input_bit_get(GPIOA, GPIO_PIN_0)== RESET)
{
gpio_bit_set(GPIOC, GPIO_PIN_13);
delay_1ms(100);
gpio_bit_reset(GPIOC, GPIO_PIN_13);
while(gpio_input_bit_get(GPIOA, GPIO_PIN_0)== RESET)
{
delay_1ms(10);
CountPressTime++;
}
if(CountPressTime>LongPressCount)
{
CountPressTime=0;
func_index = table[func_index].enter;
}
else
func_index = table[func_index].down;
}
}
}
if (func_index != last_index)
{
current_operation_index = table[func_index].current_operation;
(*current_operation_index)();
last_index = func_index;
}
};
3.PWM
使用PWM控制电机旋转。
#define BSP_PWM_RCU RCU_GPIOA
#define BSP_PWM_PORT GPIOA
#define BSP_PWM_PIN GPIO_PIN_5
#define BSP_PWM_AF GPIO_AF_1
#define BSP_PWM_TIMER_RCU RCU_TIMER1
#define BSP_PWM_TIMER TIMER1
#define BSP_PWM_CHANNEL TIMER_CH_0
static void pwm_gpio_config(void)
{
rcu_periph_clock_enable(BSP_PWM_RCU);
gpio_mode_set(BSP_PWM_PORT,GPIO_MODE_AF,GPIO_PUPD_NONE,BSP_PWM_PIN);
gpio_output_options_set(BSP_PWM_PORT,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,BSP_PWM_PIN);
gpio_af_set(BSP_PWM_PORT,BSP_PWM_AF,BSP_PWM_PIN);
}
void pwm_config(uint16_t pre,uint16_t per)
{
timer_parameter_struct timere_initpara;
timer_oc_parameter_struct timer_ocintpara;
pwm_gpio_config();
rcu_periph_clock_enable(BSP_PWM_TIMER_RCU);
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
timer_deinit(BSP_PWM_TIMER);
timere_initpara.prescaler = pre-1;
timere_initpara.alignedmode = TIMER_COUNTER_EDGE;
timere_initpara.counterdirection = TIMER_COUNTER_UP;
timere_initpara.period = per-1;
timere_initpara.clockdivision = TIMER_CKDIV_DIV1;
timere_initpara.repetitioncounter = 0;
timer_init(BSP_PWM_TIMER,&timere_initpara);
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_channel_output_config(BSP_PWM_TIMER,BSP_PWM_CHANNEL,&timer_ocintpara);
timer_channel_output_pulse_value_config(BSP_PWM_TIMER,BSP_PWM_CHANNEL,0);
timer_channel_output_mode_config(BSP_PWM_TIMER,BSP_PWM_CHANNEL,TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(BSP_PWM_TIMER,BSP_PWM_CHANNEL,TIMER_OC_SHADOW_DISABLE);
timer_auto_reload_shadow_enable(BSP_PWM_TIMER);
timer_enable(BSP_PWM_TIMER);
}
void pwm_breathing_lamp(void)
{
static uint8_t direct = 0;
static uint16_t value = 0;
if(direct == 0)
{
value += 400;
if(value > 10000)
direct = 1;
}else
{
value -= 400;
if(value <= 0)
direct = 0;
}
timer_channel_output_pulse_value_config(BSP_PWM_TIMER,BSP_PWM_CHANNEL,value);
delay_1ms(50);
}
4.ADC
使用外部光敏电阻模拟电压变化,使用ADC读取数值并计算电压。外部可接传感器电压。
uint16_t gt_adc_val[30][4];
void ADC_DMA_Init(void)
{
dma_single_data_parameter_struct dma_single_data_parameter;
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_ADC0);
rcu_periph_clock_enable(RCU_DMA1);
adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1);
gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_2);
gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_4);
adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);
adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
adc_channel_length_config(ADC0, ADC_ROUTINE_CHANNEL, 4);
adc_routine_channel_config(ADC0, 0, ADC_CHANNEL_11, ADC_SAMPLETIME_15);
adc_routine_channel_config(ADC0, 1, ADC_CHANNEL_12, ADC_SAMPLETIME_15);
adc_routine_channel_config(ADC0, 2, ADC_CHANNEL_13, ADC_SAMPLETIME_15);
adc_routine_channel_config(ADC0, 3, ADC_CHANNEL_14, ADC_SAMPLETIME_15);
adc_resolution_config(ADC0, ADC_RESOLUTION_12B);
adc_external_trigger_config(ADC0, ADC_ROUTINE_CHANNEL, EXTERNAL_TRIGGER_DISABLE);
adc_dma_request_after_last_enable(ADC0);
adc_dma_mode_enable(ADC0);
adc_enable(ADC0);
delay_1ms(1);
adc_calibration_enable(ADC0);
dma_deinit(DMA1, DMA_CH0);
dma_single_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));
dma_single_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_single_data_parameter.memory0_addr = (uint32_t)(gt_adc_val);
dma_single_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_single_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
dma_single_data_parameter.direction = DMA_PERIPH_TO_MEMORY;
dma_single_data_parameter.number = 4*30;
dma_single_data_parameter.priority = DMA_PRIORITY_HIGH;
dma_single_data_mode_init(DMA1, DMA_CH0, &dma_single_data_parameter);
dma_channel_subperipheral_select(DMA1, DMA_CH0, DMA_SUBPERI0);
dma_circulation_enable(DMA1, DMA_CH0);
dma_channel_enable(DMA1, DMA_CH0);
adc_software_trigger_enable(ADC0, ADC_ROUTINE_CHANNEL);
}
unsigned int Get_Adc_Dma_Value(char CHx)
{
unsigned char i = 0;
unsigned int AdcValue = 0;
for(i=0;i<30;i++)
{
AdcValue+=gt_adc_val[i][CHx];
}
AdcValue=AdcValue/30;
return AdcValue;
}
extern uint16_t gt_adc_val[30][4];
unsigned int Get_Adc_Dma_Value(char CHx);
uint8_t str_buff[64];
uint16_t ADC_Value = 0;
uint16_t ADC_Volt = 0;
unsigned char temp_buff[200];
unsigned int show_buff[4];
void OLED_display_dat()
{
sprintf((char *)temp_buff, "%4d",show_buff[0]);
OLED_ShowString1(64,3,(uint8_t *)temp_buff);
ADC_Value=show_buff[0];
ADC_Volt = ADC_Value * 330 / 4096;
sprintf((char*)temp_buff, "%d.%d%dV", ADC_Volt/100, (ADC_Volt%100)/10, ADC_Volt%10);
OLED_ShowString1(64,6,(uint8_t *)temp_buff);
}
5.串口
串口可打印参数
void usart_gpio_config(uint32_t band_rate)
{
rcu_periph_clock_enable(BSP_USART_TX_RCU);
rcu_periph_clock_enable(BSP_USART_RX_RCU);
rcu_periph_clock_enable(BSP_USART_RCU);
gpio_af_set(BSP_USART_TX_PORT,BSP_USART_AF,BSP_USART_TX_PIN);
gpio_af_set(BSP_USART_RX_PORT,BSP_USART_AF,BSP_USART_RX_PIN);
gpio_mode_set(BSP_USART_TX_PORT,GPIO_MODE_AF,GPIO_PUPD_PULLUP,BSP_USART_TX_PIN);
gpio_mode_set(BSP_USART_RX_PORT, GPIO_MODE_AF,GPIO_PUPD_PULLUP,BSP_USART_RX_PIN);
gpio_output_options_set(BSP_USART_TX_PORT,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,BSP_USART_TX_PIN);
gpio_output_options_set(BSP_USART_RX_PORT,GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, BSP_USART_RX_PIN);
usart_deinit(BSP_USART);
usart_baudrate_set(BSP_USART,band_rate);
usart_parity_config(BSP_USART,USART_PM_NONE);
usart_word_length_set(BSP_USART,USART_WL_8BIT);
usart_stop_bit_set(BSP_USART,USART_STB_1BIT);
usart_enable(BSP_USART);
usart_transmit_config(BSP_USART,USART_TRANSMIT_ENABLE);
}
void usart_send_data(uint8_t ucch)
{
usart_data_transmit(BSP_USART,(uint8_t)ucch);
while(RESET == usart_flag_get(BSP_USART,USART_FLAG_TBE));
}
void usart_send_string(uint8_t *ucstr)
{
while(ucstr && *ucstr)
{
usart_send_data(*ucstr++);
}
主函数
主函数的配置
systick_config();
rcu_periph_clock_enable(RCU_GPIOC);
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
rcu_periph_clock_enable(RCU_GPIOA);
gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_0);
rcu_periph_clock_enable(RCU_GPIOC);
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_13);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
gpio_bit_set(GPIOC, GPIO_PIN_6);
delay_1ms(1000);
gpio_bit_reset(GPIOC, GPIO_PIN_6);
delay_1ms(1000);
OLED_Init();
OLED_ColorTurn(0);
OLED_Clear(1);
delay_1ms(500);
OLED_Clear(0);
OLED_ShowPicture(0,0,128,64,BMP1,1);
OLED_Refresh();
delay_1ms(1000);
OLED_Clear(0);
rcu_periph_clock_enable(RCU_GPIOA);
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_1);
pwm_config(200,10000);
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
systick_config(); ADC_DMA_Init();
While函数
Scan_Keys_OLED();
switch(func_index)
{
case 7:
pwm_breathing_lamp();
break;
case 8:
show_buff[0] = Get_Adc_Dma_Value(0);
OLED_display_dat();
OLED_display_info();
break;
case 9:
delay_1ms(500);
break;
}
原作者:兆易创新GD32 MCU 时光正好