自从接受linux的熏陶来,编程思想已经发生极大转变(提高)。下面是由request gpio,及注册式驱动启发,在freertos上实现led灯服务。该服务可提供:led控制常关方式,常开方式,闪烁方式。每个控制任务都可单独设定时间,周期频率,还有各自优先级。
指导思想:开一个周期性任务,该任务周期是20ms计(鉴于人的视觉残留是20ms)。该任务中统计led控制请求中最高优先级控制任务中GPIO的状态,完成后,再对相应的GPIO进行操作。
具体实施:首先两个链表,分别维护led控制任务列表,led请求的gpio列表。
typedef struct LEDServerTypeDef
{
struct list_head entry; //链表节点
char* name; //控制任务名称
GPIOConf_t gpioConf; //控制任务GPIO的配置
LEDLightTypeDef type; //显示方式
uint32_t ticks; //控制任务生存时间
uint32_t cycle; //半周期(闪烁方式有效)
uint32_t cc; //半周期内的计数变量
uint32_t bltime; //半周期(亮)内闪烁次数
uint32_t blcount; //半周期(亮)内的计数变量
uint32_t blactive; //半周期(亮)闪烁使能
xSemaphoreHandle lock;//访问锁
GPIOServer_t *gpio;//请求的gpio handle
}LEDServer_t;
typedef struct GPIOServerTypeDef{
struct list_head entry; //链表节点
uint16_t link; //请求连接数
GPIO_TypeDef *GPIOx; //GPIOA/B/C/D/E/F
uint16_t GPIO_Pin; //GPIO Pin脚
PriorityTypeDef curMaxPrio; //当前有效的最高优先级
GPIO_PinState set; //设置值
GPIO_PinState state; //当前状态值
}GPIOServer_t;
结构中其他定义:
typedef enum{
PRIORITY_LOW,
PRIORITY_NORMAL,
PRIORITY_HIGH,
}PriorityTypeDef;//优先级
typedef enum{
LED_STATE_ON,
LED_STATE_OFF,
}LEDStateTypeDef;//LED状态
typedef enum{
LED_ON,
LED_OFF,
LED_BLINK,
}LEDLightTypeDef;//LED控制方式
typedef struct GPIOConfigTypeDef{
PriorityTypeDef priority; //GPIO优先级
GPIO_TypeDef *GPIOx; //GPIOA/B/C/D/E/F
uint16_t GPIO_Pin; //GPIO Pin脚
GPIO_PinState gpio_led_on; //gpio 设置该值时led灯亮
}GPIOConf_t;//GPIO的配置
GPIO链表的创建和释放:
static LIST_HEAD(gGPIOListHead);
GPIOServer_t* requestGPIO(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
struct list_head *pos;
GPIOServer_t *sGpio;
list_for_each(pos, &gGPIOListHead){
sGpio = list_entry(pos, GPIOServer_t, entry);
if(GPIOx == sGpio->GPIOx &&
GPIO_Pin == sGpio->GPIO_Pin){
sGpio->link ++;
return sGpio;
}
}
sGpio = pvPortMalloc(sizeof(GPIOServer_t));
if(sGpio == NULL){
return NULL;
}
sGpio->GPIOx = GPIOx;
sGpio->GPIO_Pin = GPIO_Pin;
sGpio->link ++;
sGpio->set = GPIO_PIN_RESET;
sGpio->state = HAL_GPIO_ReadPin(GPIOx, GPIO_Pin);
sGpio->curMaxPrio = PRIORITY_LOW;
list_add(&sGpio->entry, &gGPIOListHead);
return sGpio;
}
void freeGPIO(GPIOServer_t *gpio)
{
struct list_head *pos, *n;
GPIOServer_t *sGpio;
if(gpio == NULL)
return;
if(list_empty(&gGPIOListHead))
return;
list_for_each_safe(pos, n, &gGPIOListHead){
sGpio = list_entry(pos, GPIOServer_t, entry);
if(sGpio == gpio){
sGpio->link--;
if(sGpio->link == 0){
list_del(&sGpio->entry);
vPortFree(sGpio);
return;
}
}
}
//no regisist gpio, it does not suppose to be here;
vPortFree(sGpio);
}
GPIO根据优先级设定控制值
LEDStateTypeDef getLEDState(GPIOServer_t *gpio, GPIO_PinState gpio_led_on)
{
return gpio->state == gpio_led_on? LED_STATE_ON: LED_STATE_OFF;
}
void controlGPIO(GPIOServer_t *gpio, PriorityTypeDef prio, GPIO_PinState set)
{
if(prio >= gpio->curMaxPrio){
gpio->set = set;
gpio->curMaxPrio = prio;
}
}
void controlLED(GPIOServer_t *gpio, GPIOConf_t *conf, LEDStateTypeDef set_led)
{
GPIO_PinState set_gpio;
set_gpio = (set_led == LED_STATE_ON)? conf->gpio_led_on: (GPIO_PinState)!conf->gpio_led_on;
controlGPIO(gpio, conf->priority, set_gpio);
}
LED控制链表的创建和释放
static LIST_HEAD(gLEDServerListHead);/* 获取控制任务 */
LEDServer_t *getLED(char* name)
{
struct list_head *pos;
LEDServer_t *sLed;
if(name == NULL)
return NULL;
list_for_each(pos, &gLEDServerListHead){
sLed = list_entry(pos, LEDServer_t, entry);
if(!strcmp(sLed->name, name))
return sLed;
}
return NULL;
}
/* 请求or设置控制任务 */
int setLED(LEDServer_t *led)
{
struct list_head *pos;
LEDServer_t *sLed;
if(led == NULL)
return -1;
list_for_each(pos, &gLEDServerListHead){
sLed = list_entry(pos, LEDServer_t, entry);
if(!strcmp(sLed->name, led->name)){
xSemaphoreTake(sLed->lock, portMAX_DELAY);
if(sLed->gpioConf.GPIOx != led->gpioConf.GPIOx //如果设置的led控制gpio不同
|| sLed->gpioConf.GPIO_Pin != led->gpioConf.GPIO_Pin){
GPIOServer_t *gpio = requestGPIO(sLed->gpioConf.GPIOx, sLed->gpioConf.GPIO_Pin);//请求gpio
if(gpio){//
freeGPIO(sLed->gpio);
sLed->gpio = gpio; //重新设定gpio
sLed->gpioConf.GPIOx = led->gpioConf.GPIOx;
sLed->gpioConf.GPIO_Pin = led->gpioConf.GPIO_Pin;
}
}
sLed->gpioConf.priority = led->gpioConf.priority; //设置其他参数
sLed->gpioConf.gpio_led_on = led->gpioConf.gpio_led_on;
sLed->gpioConf = led->gpioConf;
sLed->type = led->type;
sLed->ticks = led->ticks;
sLed->cycle = led->cycle;
sLed->bltime = led->bltime;
sLed->blcount = led->blcount;
sLed->blactive = led->blactive;
xSemaphoreGive(sLed->lock);
return 0;
}
}
//新的led控制任务
sLed = pvPortMalloc(sizeof(LEDServer_t));
if(sLed == NULL){
return -1;
}
memcpy(sLed, led, sizeof(LEDServer_t));
sLed->lock = xSemaphoreCreateMutex();
if(sLed->lock == NULL){
vPortFree(sLed);
return -1;
}
//请求gpio
sLed->gpio = requestGPIO(sLed->gpioConf.GPIOx, sLed->gpioConf.GPIO_Pin);
if(sLed->gpio == NULL){
vPortFree(sLed);
return -1;
}
list_add(&sLed->entry, &gLEDServerListHead);
return 0;
}
/* 取消led控制任务 */
void unsetLED(char* name)
{
struct list_head *pos, *n;
LEDServer_t *sLed;
if(name == NULL)
return;
if(list_empty(&gLEDServerListHead))
return;
list_for_each_safe(pos, n, &gLEDServerListHead){
sLed = list_entry(pos, LEDServer_t, entry);
if(!strcmp(sLed->name, name)){
list_del(&sLed->entry);
freeGPIO(sLed->gpio);
vSemaphoreDelete(sLed->lock);
vPortFree(sLed);
}
}
}
周期性控制任务
static void LEDServerTask(void const * argument)
{
uint32_t freq = 20;
struct list_head *pos;
LEDServer_t *sLed;
LEDStateTypeDef led_state;
GPIOServer_t *sGpio;
while(1){
//led 控制任务循环检测
list_for_each(pos, &gLEDServerListHead){
sLed = list_entry(pos, LEDServer_t, entry);
xSemaphoreTake(sLed->lock, portMAX_DELAY);
switch(sLed->type)
{
case LED_ON:
if(sLed->ticks > 0){
controlLED(sLed->gpio, &sLed->gpioConf, LED_STATE_ON);
}
break;
case LED_OFF:
controlLED(sLed->gpio, &sLed->gpioConf, LED_STATE_OFF);
break;
case LED_BLINK:
if(sLed->ticks > 0){
if(sLed->bltime > 1 && sLed->blactive && sLed->cc < sLed->cycle){//半周期(亮)闪烁控制
if(sLed->blcount > sLed->cycle/(sLed->bltime*2-1)){
led_state = getLEDState(sLed->gpio, sLed->gpioConf.gpio_led_on);
controlLED(sLed->gpio, &sLed->gpioConf, (LEDStateTypeDef)!led_state);
sLed->blcount = 0;
}
sLed->blcount += freq;
}
if(sLed->cc >= sLed->cycle){
led_state = getLEDState(sLed->gpio, sLed->gpioConf.gpio_led_on);
controlLED(sLed->gpio, &sLed->gpioConf, (LEDStateTypeDef)!led_state);//翻转
sLed->cc = 0;
sLed->blcount = 0;
if(led_state == LED_STATE_OFF)//翻转前状态
sLed->blactive = 1;//半周期(亮)状态设置
else
sLed->blactive = 0;
}
sLed->cc += freq;
}
break;
default :
break;
}
if(sLed->ticks != portMAX_DELAY){
if(sLed->ticks != 0){
if(sLed->ticks > freq){
sLed->ticks -= freq;//控制任务生存计时
}
else{
sLed->ticks = 0;//结束
sLed->cc = 0;
controlLED(sLed->gpio, &sLed->gpioConf, LED_STATE_OFF);//shout down
}
}
}
xSemaphoreGive(sLed->lock);
}
//gpio 控制操作
list_for_each(pos, &gGPIOListHead){
sGpio = list_entry(pos, GPIOServer_t, entry);
if(sGpio->set != sGpio->state){//避免频繁操作,不同状态才可实际行动
HAL_GPIO_WritePin(sGpio->GPIOx, sGpio->GPIO_Pin, sGpio->set);
sGpio->state = sGpio->set;
sGpio->curMaxPrio = PRIORITY_LOW;//复位优先级,为下次做准备
}
}
osDelay(freq);
}
}
实例
static void led_running_blink()
{
LEDServer_t led;
led.name = "Run";
led.gpioConf.GPIOx = GPIOC;
led.gpioConf.GPIO_Pin = GPIO_PIN_5;
led.gpioConf.gpio_led_on = GPIO_PIN_RESET;
led.gpioConf.priority = PRIORITY_LOW;
led.type = LED_BLINK;
led.ticks = portMAX_DELAY;
led.cycle = 1000;
led.cc = 0;
led.bltime = 0;
led.blcount = 0;
led.blactive = 0;
setLED(&led);
}
以上还可以扩展很多led的控制方式。
下次介绍注册式驱动的实现,其实也和上面思想一致,从注册的驱动链表中,适配适合的硬件ID然后返回驱动Handle