学习笔记(二)——裸机开发程序框架

以读取一个按键状态为例

1.宏开关:只能支持一个版本按键

#define HARDWARE_VER  1

// key.c
// 返回值: 0表示被按下, 1表示被松开
int read_key(void)
{
    GPIO_PinState key;
#if (HARDWARE_VER == 1)
    key = HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_6);
#else
    key = HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_7);
#endif
    if (key == GPIO_PIN_RESET)
        return 0;
    else
        return 1;            
}

2.使用函数指针

int (*read_key)(void);

// 返回值: 0表示被按下, 1表示被松开
int read_key_ver1(void)
{
    GPIO_PinState key;
    key = HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_6);
    if (key == GPIO_PIN_RESET)
        return 0;
    else
        return 1;            
}

// 返回值: 0表示被按下, 1表示被松开
int read_key_ver2(void)
{
    GPIO_PinState key;
    key = HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_6);
    if (key == GPIO_PIN_RESET)
        return 0;
    else
        return 1;            
}

void key_init()
{
    int ver = read_hardware_ver(); //读取硬件版本
    if (ver == 1)
        read_key = read_key_ver1;
    else
        read_key = read_key_ver2;
}

// main.c
void main(void)
{
    int key;
    
    key_init();
    
    while (1)
    {
        key = read_key();
        if (key == UP)
            led_on();
        else
            led_off();
    }
}

3.但如果要同时支持多个版本,并且容易拓展,最好是使用结构体并且函数分层模块化

typedef struct key{
    char *name;
    int (*init)(struct key *k);
    int (*read)(struct key *k);
}key,*p_key;

定义一个key结构体,包涵名字,初始化函数和读取函数。让每个按键都实现结构体

//key1.c
key k1 = {"k1".NULL,read_key1};

//key2.c
key k2 = {"k2".NULL,read_key2};

//key3.c
key k3 = {"k3".NULL,read_key3};

将底层分为k1.,k2,k3按键的初始化+读取,将每个按键的结构体数据放在中间层进行注册管理(key.manager),最后将key.manager处理得到的按键数据传回应用层供main使用。

//key.manager.c
int key_cnt = 0;
key *keys[32];


int register_key(key *k)  //注册按键,也就是把按键数据存入数组/链表
{
    keys[key_cnt] = k;
    key_cnt ++;
}

void key_init(void)
{
    k1_init;
    k2_init;
}

key *get_key(char *name)  //得到按键数据
{
    ibt i = 0;
    for(i=0;i<key_cnt;i++)
    {
        if(strcmp(name,key[i)->name) == 0)
        {
            return keys[i];
        }
    }
    return NULL;
}

int read_key(void)
{
	int val;
	int i = 0; 
	for (i = 0; i < key_cnt; i++)
	{
		val = keys[i]->read(keys[i]); 
		if (val == -1)
			continue;
		else
			return val;
	}

	return -1;
}


//k1.c  k2同理
static int read_key1(void)
{
    GPIO_PinState key;
    key = HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_6);
    if (key == GPIO_PIN_RESET)
        return 0;
    else
        return 1;
}


static key k1 = {"k1", k1_init, read_key1};

void k1_init(void)
{
	register_key(&k1);
}



//main.c
int main()
{
    key_init();
    key *k;
    k = get_key("k1");
    if(k == NULL)
    return ;
    
    while(1)
    {
        if(k->read(k) == 0)
        led_on();
        else led_off();
    }
}

这样可以通过修改get_key传入的参数来获取按键的值,但是如何做到自动分辨按键值并且支持多个按键呢?

首先是在结构体里再加入一个code元素来分辨按键。

typedef struct key {
	char *name;
	int code;
    void (*init)(struct key *k);
    int (*read)(struct key *k);
}key, *p_key;

key k1={"k1",0xA,k1_init,read_key1};

并且修改read_key函数,通过main轮询查按键

//k1.c

static int read_key1(void)
{
    GPIO_PinState key;
    static GPIO_PinState pre_key;
    key = HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_6);

    if (key == pre_key) //按键无变化
        return -1;

    pre_key = key;//按键发生变化

    if(key == GPIO_PIN_RESET)
        return 0xA | (1<<7); //按下按键
    else
        return 0xA;
}

//key.manager.c

int read_key(void)
{
    int val;
    int i=0;
    for(i=o;i<key_cnt;i++)
    {
        val = keys[i]->read(keys[i])
        if(val == -1)
            continue;
        else 
            return val;
    }
    return -1;
}

//main.c

void main(void)
{
	key *k;
	int val;
	key_init();	
    
    while(1)
    {
        val = read_key();
        if(val == -1)
        {}
        else 
        {
            switch(val)
            {
                case 0xA: /* k1 松开 */

		    	case 0xA|(1<<7) : /* k1 按下 */
                case ...
            }
        }
    }

但是轮询的方式远不如用中断效率高,采用中断函数来保存每个按键的val,并且将val保存到一个buf数组里,在manager里直接通过读取buf数组就可以知道按键值。

//k1.c
void k1_isr(void)
{
    GPIO_PinState key;
    key = HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_6);

	/* 按键发生了变化 */
    if (key == GPIO_PIN_RESET)
        put_buf(0xA | (1<<7));   //将数值存入buf
    else
        put_buf(0xA) ;
}

//keymanager.c

int data_buf[100];

int read_key(void)
{
    return get_buf(); //直接读取buf
}

int put_buf(int buf) //将数据存入data_buf
{
  
}

int get_buf( ) //把数据从data_buf拿出
{

}

大致结构如下 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
cda备考学习学习笔记——基础知识篇()主要涉及了计算机科学与技术领域的基本概念和知识。 首先,它介绍了计算机网络的基础知识。网络是将多台计算机通过通信链路连接起来,使它们能够相互通信和共享资源的系统。笔记中详细介绍了网络的组成、拓扑结构和通信协议等重要内容。 其次,笔记还解释了计算机系统的基本组成。计算机系统由硬件和软件两部分组成,其中硬件包括中央处理器、存储器、输入输出设备等,而软件则分为系统软件和应用软件。笔记详细介绍了各种硬件和软件的功能和作用。 此外,笔记还对数据库管理系统进行了介绍。数据库管理系统是一种用于管理和组织数据的软件系统,它能够实现数据的存储、检索和更新等操作。笔记中详细介绍了数据库的概念、结构和操作等内容。 最后,笔记还包括了算法和数据结构的基础知识。算法是解决问题的一系列步骤和规则,而数据结构则是组织和存储数据的方式。笔记中介绍了常用的算法和数据结构,如排序算法、树和图等。 总之,通过学习CDA备考学习笔记中的基础知识篇(),我们能够更好地理解计算机网络、计算机系统、数据库管理系统以及算法和数据结构等相关概念和知识。这些基础知识对于我们深入研究计算机科学与技术领域是非常重要的,也为我们日后的学习和工作奠定了坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值