首先感谢极术社区、安谋科技学堂以及兆易创新给与的评测机会!
背景:
在刷朋友圈的时候突然刷到极术社区的赠书活动,填完抽奖表后发现还有一个GD32F3苹果派开发板测评活动,目前从事新能源领域的工作,刚好一直再用GD32系列的单片机,索性就参加了测评活动。
首先,我们来做一下芯片参数的硬件测评,也就拿我们的32位MCU的老大哥STM32来跟我们的国产单片机一哥来进行对比,数据部分来自立创商城,不过稍微瞄了一眼数据手册发现立创商城里登记的部分参数不太对,最后还是根据芯片手册改了一下,仅供参考。
个人总结:根据立创商城的价格来看GD32F303ZET6比STM32F303ZET6的价格低了25%左右,120MHz主频比72MHz主频提升66%,有没有一种买电脑挑CPU的感觉?其次,外设大家都差不多,值得一提的是兆易创新是做NOR FLASH出身所以芯片内的FLASH是自主研发的,根据芯片手册该款芯片具有256KB的零等待区,简单点来说代码执行更快没有延迟,有兴趣的小伙伴可以自己去深入了解一下。
测评想法:
制作使用RTThread的一个PWM调光器(点灯大师),使用一个RGB三原色灯珠,采用3路PWM进行调光控制,用板载的三个按键进行控制,此控制器无论灯珠多少皆可适用。
测评历程:
本人也在公司里参与灯光造型方案的研发和设计,不过比这个会高级很多,由于日常996加上自己很喜欢学东西,基本上也就和007没差了,时间不太够,也是晚上顶着熬夜来写的,刚开始想加的东西很多,RS485和CAN通信,甚至是阿里云平台,后来一估算时间发现根本做不完,这些东西就都砍掉了,最后剩下一个RTOS和PWM调光,主要也是体验苹果派开发板为主。
本人平时从事的工作也是关于GD32系列单片机开发,所以基本GD32系列单片机大部分都有接触过。
同时也比较期待最近发布的GD32H7的开发板,能给我们带来更多的体验。
代码分享:
由于一开始想做的很多,结果框架越搭越大,最后也是无奈时间有限就砍掉了,但是框架还是在的,在嵌入式后期的话架构是很重要的。
软件架构分为驱动层、中间层、应用层。
使用的是MDK自带的RTThtrad组件,方便易用。
下面是代码部分
static rt_sem_t beep_sem = RT_NULL; //蜂鸣器信号量
static rt_event_t rgb_led_event = RT_NULL; //RGB灯事件集
static rt_mq_t key_mq = RT_NULL; //按键消息队列
static rt_mq_t duoji_mq = RT_NULL;
//舵机消息队列,用于传输1字节的指令,
//0:舵机正传+1°
//1: 舵机反转+1°
//2:舵机以每秒10°的速度正转,直到极限角度
//3:舵机以每秒10°的速度反转,直到极限角度
static led_struct led = {0};
void rgb_led_thread_entry(void *parameter)
{
uint8_t key_value = 0;
while(1)
{
//获取按键值完成相应的操作
if(RT_EOK == rt_mq_recv(key_mq,&key_value,1,RT_WAITING_FOREVER))
{
switch(key_value)
{
case 1:led_light_add(&led);break;//增加某一颜色亮度
case 2:led_colour_change(&led);break;//切换某一颜色
case 3:led_light_reduce(&led);break;//减少某一颜色亮度
}
}
rt_thread_mdelay(100);
}
}
void duoji_thread_entry(void *parameter)
{
while(1)
{
rt_thread_mdelay(500);
}
}
void beep_thread_entry(void *parameter)
{
//按键按下将获取一次信号量
while(1)
{
if(rt_sem_take(beep_sem,RT_WAITING_FOREVER) == RT_EOK)
{
beep_once();
}
}
}
void key_thread_entry(void *parameter)
{//50ms读取一次按键,使用状态机判断长按和短按,利用消息队列传递指令
while(1)
{
uint8_t key_num = key_read(); //获取按键按下值
rt_mq_send(key_mq,&key_num,1); //按键值压入消息队列
key_response(key_num,beep_sem); //按一下蜂鸣器响一下
key_clear(); //按键状态清除
rt_thread_mdelay(50);
}
}
int rgb_led_thread_init(void)
{
/* RGB灯动态线程 */
rgb_led_thread = rt_thread_create("rgb_led_thread",
rgb_led_thread_entry,RT_NULL,
RGB_LED_THREAD_STACK_SIZE,
RGB_LED_THREAD_PRIORITY,
RGB_LED_THREAD_TIMESLICE);
if(rgb_led_thread != RT_NULL)
rt_thread_startup(rgb_led_thread);
else
return RT_ERROR;
return RT_EOK;
}
int duoji_thread_init(void)
{
/* 舵机动态线程 */
duoji_thread = rt_thread_create("duoji_thread",
duoji_thread_entry,RT_NULL,
DUOJI_THREAD_STACK_SIZE,
DUOJI_THREAD_PRIORITY,
DUOJI_THREAD_TIMESLICE);
if(duoji_thread != RT_NULL)
rt_thread_startup(duoji_thread);
else
return RT_ERROR;
return RT_EOK;
}
int beep_thread_init(void)
{
beep_sem = rt_sem_create("beep_sem",0,RT_IPC_FLAG_FIFO);
/* 蜂鸣器动态线程 */
beep_thread = rt_thread_create("beep_thread",
beep_thread_entry,RT_NULL,
BEEP_THREAD_STACK_SIZE,
BEEP_THREAD_PRIORITY,
BEEP_THREAD_TIMESLICE);
if(beep_thread != RT_NULL)
rt_thread_startup(beep_thread);
else
return RT_ERROR;
return RT_EOK;
}
int key_thread_init(void)
{
key_mq = rt_mq_create("key_mq",1,10,RT_IPC_FLAG_FIFO);
/* 按键动态线程 */
key_thread = rt_thread_create("key_thread",
key_thread_entry,RT_NULL,
KEY_THREAD_STACK_SIZE,
KEY_THREAD_PRIORITY,
KEY_THREAD_TIMESLICE);
if(key_thread != RT_NULL)
rt_thread_startup(key_thread);
else
return RT_ERROR;
return RT_EOK;
}
/* 控制器线程初始化 */
int controller_thread_init(void)
{
rgb_led_thread_init();
duoji_thread_init();
beep_thread_init();
key_thread_init();
return RT_EOK;
return RT_ERROR;
}
INIT_APP_EXPORT(controller_thread_init);`
![image.png](/img/bVb2df)
`key_struct key[4];
/* 按键读取函数 */
uint8_t key_read(void)
{
if(gpio_input_bit_get(KEY1_PORT,KEY1_PIN))
{
return 1;
}
if(gpio_input_bit_get(KEY2_PORT,KEY2_PIN) == RESET)
{
return 2;
}
if(gpio_input_bit_get(KEY3_PORT,KEY3_PIN) == RESET)
{
return 3;
}
return 0;
}
/* 按键响应函数 */
void key_response(uint8_t num,rt_sem_t beep_sem)
{
if(key[num].state == RELEASE && num != 0)
{
key[num].state = PRESS;
rt_sem_release(beep_sem);
}
}
/* 按键数据清理函数 */
void key_clear(void)
{
if(gpio_input_bit_get(KEY1_PORT,KEY1_PIN) == RESET)
{
key[1].state = RELEASE;
}
if(gpio_input_bit_get(KEY2_PORT,KEY2_PIN) == SET)
{
key[2].state = RELEASE;
}
if(gpio_input_bit_get(KEY3_PORT,KEY3_PIN) == SET)
{
key[3].state = RELEASE;
}
}
/* 蜂鸣器响应一次 */
void beep_once(void)
{
gpio_bit_set(BEEP_PORT,BEEP_PIN);
rt_thread_mdelay(30);
gpio_bit_reset(BEEP_PORT,BEEP_PIN);
}
void led_red_set(uint8_t bright)
{
timer_channel_output_pulse_value_config(TIMER1,TIMER_CH_1,bright);
}
void led_green_set(uint8_t bright)
{
timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_0,bright);
}
void led_blue_set(uint8_t bright)
{
timer_channel_output_pulse_value_config(TIMER3,TIMER_CH_0,bright);
}
void led_light_add(led_struct *led)
{
switch(led->state)
{
case RED_MODE:
{
led->red_light++;
led_red_set(led->red_light);
}
break;
case GREEN_MODE:
{
led->green_light++;
led_green_set(led->green_light);
}
break;
case BLUE_MODE:
{
led->blue_light++;
led_blue_set(led->blue_light);
}
default:
break;
}
}
void led_light_reduce(led_struct *led)
{
switch(led->state)
{
case RED_MODE:
{
led->red_light--;
led_red_set(led->red_light);
}
break;
case GREEN_MODE:
{
led->green_light--;
led_green_set(led->green_light);
}
break;
case BLUE_MODE:
{
led->blue_light--;
led_blue_set(led->blue_light);
}
default:
break;
}
}
void led_colour_change(led_struct *led)
{
static uint8_t mode = 0;
mode++;
switch(mode)
{
case 0:led->state = RED_MODE;
case 1:led->state = GREEN_MODE;
case 2:led->state = BLUE_MODE;
}
}
`
![image.png](/img/bVb2dg)
`typedef enum
{
RED,
GREEN,
BLUE,
YELLOW,
}rgb_colour;
typedef struct
{
rgb_colour colour;
}rgb_led;//RGB灯状态
typedef enum
{
RELEASE, //松开
PRESS, //按下
}key_state;//按键状态
typedef enum
{
RED_MODE,
GREEN_MODE,
BLUE_MODE,
}led_state;//灯光模式选择
typedef struct
{
key_state state;
}key_struct;//按键状态机
typedef struct
{
led_state state;
uint8_t red_light;
uint8_t green_light;
uint8_t blue_light;
}led_struct;//灯光控制状态机
extern uint8_t key_read(void);
extern void beep_once(void);
extern void key_response(uint8_t num,rt_sem_t beep_sem);
extern void key_clear(void);
extern void led_colour_change(led_struct *led);
extern void led_light_reduce(led_struct *led);
extern void led_light_add(led_struct *led);
后面写的比较赶,没去考虑复用性,大家看看就好了。
这个是PWM调光器的样子,虽然只有一颗灯珠但本质是通用的,我做的灯光控制方案的话涉及到上千个灯珠,同时每个灯珠需要单独控制,能实现1600万种颜色自由变换,整套方案仅仅使用一个IO口实现,略微夸张但事实也是这样的。
个人感想:
在嵌入式前期的学习过程中注重对于各类外设,通信协议的融会贯通,后期更靠软件架构设计,所以在工作中积累经验的同时要注重培养自己的软件架构思维。要成为一名合格的嵌入式工程师就要保持自己终身学习的习惯,海纳百川,这也是我为什么会选择成为一名嵌入式工程师的原因之一。
再次感谢极术社区、安谋科技学堂以及兆易创新给与的评测机会!