1. BSP-board support package , 主要针对板子的底层做了支持。 用bsp接口调用底层硬件可以降低硬件相关性。 对于nordic平台来说,BSP的底层硬件主要关联到灯和按键,这部分定义在boards.h中根据编译选项关联到对应的板子h文件,我们自定义的板子为hy0628.h

板子的.h文件主要就是灯和按键的引脚关联和数量,状态等定义,这部分是基本的

// LEDs definitions for dev 0628
#define LEDS_NUMBER    3#define B_LED          9
#define R_LED          7
#define G_LED         5
#define LEDS_LIST { B_LED, R_LED, G_LED }
#define B_LED_Toggle nrf_gpio_pin_toggle(B_LED)
#define R_LED_Toggle nrf_gpio_pin_toggle(R_LED)
#define G_LED_Toggle nrf_gpio_pin_toggle(G_LED)
#define BSP_LED_0      B_LED
#define BSP_LED_1      R_LED
#define BSP_LED_2      G_LED#define LEDS_ACTIVE_STATE 0#define BUTTONS_NUMBER 3#define  USR_KEY1    2
#define  USR_KEY2    3
#define  USR_KEY3    4
#define BUTTONS_LIST { USR_KEY1, USR_KEY2, USR_KEY3}#define BUTTONS_ACTIVE_STATE 0
#define BUTTON_PULL    NRF_GPIO_PIN_PULLUP#define BSP_BUTTON_0   USR_KEY1
#define BSP_BUTTON_1   USR_KEY2
#define BSP_BUTTON_2   USR_KEY3

2. bsp.h里定义了板级的标准事件

typedef enum
{BSP_EVENT_NOTHING = 0,                  /**< Assign this event to an action to prevent the action from generating an event (disable the action). */BSP_EVENT_DEFAULT,                      /**< Assign this event to an action to assign the default event to the action. */BSP_EVENT_CLEAR_BONDING_DATA,           /**< Persistent bonding data should be erased. */BSP_EVENT_CLEAR_ALERT,                  /**< An alert should be cleared. */BSP_EVENT_DISCONNECT,                   /**< A link should be disconnected. */BSP_EVENT_ADVERTISING_START,            /**< The device should start advertising. */BSP_EVENT_ADVERTISING_STOP,             /**< The device should stop advertising. */BSP_EVENT_WHITELIST_OFF,                /**< The device should remove its advertising whitelist. */BSP_EVENT_BOND,                         /**< The device should bond to the currently connected peer. */BSP_EVENT_RESET,                        /**< The device should reset. */BSP_EVENT_SLEEP,                        /**< The device should enter sleep mode. */BSP_EVENT_WAKEUP,                       /**< The device should wake up from sleep mode. */BSP_EVENT_SYSOFF,                       /**< The device should enter system off mode (without wakeup). */BSP_EVENT_DFU,                          /**< The device should enter DFU mode. */BSP_EVENT_KEY_0,                        /**< Default event of the push action of BSP_BUTTON_0 (only if this button is present). */BSP_EVENT_KEY_1,                        /**< Default event of the push action of BSP_BUTTON_1 (only if this button is present). */BSP_EVENT_KEY_2,                        /**< Default event of the push action of BSP_BUTTON_2 (only if this button is present). */BSP_EVENT_KEY_3,                        /**< Default event of the push action of BSP_BUTTON_3 (only if this button is present). */BSP_EVENT_KEY_4,                        /**< Default event of the push action of BSP_BUTTON_4 (only if this button is present). */BSP_EVENT_KEY_5,                        /**< Default event of the push action of BSP_BUTTON_5 (only if this button is present). */BSP_EVENT_KEY_6,                        /**< Default event of the push action of BSP_BUTTON_6 (only if this button is present). */BSP_EVENT_KEY_7,                        /**< Default event of the push action of BSP_BUTTON_7 (only if this button is present). */BSP_EVENT_KEY_LAST = BSP_EVENT_KEY_7,
} bsp_event_t;

3. 按键也有按下触发,释放触发或长按

typedef struct
{bsp_event_t push_event;      /**< The event to fire on regular button press. */bsp_event_t long_push_event; /**< The event to fire on long button press. */bsp_event_t release_event;   /**< The event to fire on button release. */
} bsp_button_event_cfg_t;

4. 问题来了,如何在触发事件--状态切换--响应事件之间建立关联关系呢? 

先看主程序,很简单,初始化,然后就低功耗等待了,所以中断,时钟调度,状态切换等都交给bsp去干活了,主循环不需要执行什么。下一个问题是:  如果要自定义功能呢? 留待下个例程分解

int main(void)
{clock_initialization();uint32_t err_code = app_timer_init();APP_ERROR_CHECK(err_code);APP_ERROR_CHECK(NRF_LOG_INIT(NULL));NRF_LOG_DEFAULT_BACKENDS_INIT();NRF_LOG_INFO("BSP example started.");bsp_configuration();while (true){NRF_LOG_FLUSH();__SEV();__WFE();__WFE();// no implementation needed}
}

应该BSP是有个timer来调度资源的,所以主程序一开始,先要clock配置和调用app_timer_init()

void clock_initialization()
{NRF_CLOCK->LFCLKSRC            = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;NRF_CLOCK->TASKS_LFCLKSTART    = 1;while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0){// Do nothing.}
}

app_timer_init()应该是标准函数,定义了rtc和overflow的处理

5. 来看bsp_configuration()干了啥

void bsp_configuration()
{uint32_t err_code;err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_evt_handler);APP_ERROR_CHECK(err_code);
}

调用了bsp_init(),这个是标准函数还是自定义? 在bsp.c里,建立了触发条件和事件之间的关联

uint32_t bsp_init(uint32_t type, bsp_event_callback_t callback)
{uint32_t err_code = NRF_SUCCESS;#if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)m_indication_type     = type;
#endif // LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)#if (BUTTONS_NUMBER > 0) && !(defined BSP_SIMPLE)m_registered_callback = callback;// BSP will support buttons and generate eventsif (type & BSP_INIT_BUTTONS){uint32_t num;for (num = 0; ((num < BUTTONS_NUMBER) && (err_code == NRF_SUCCESS)); num++){err_code = bsp_event_to_button_action_assign(num, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_DEFAULT);}if (err_code == NRF_SUCCESS){err_code = app_button_init((app_button_cfg_t *)app_buttons,BUTTONS_NUMBER,APP_TIMER_TICKS(50));}if (err_code == NRF_SUCCESS){err_code = app_button_enable();}if (err_code == NRF_SUCCESS){err_code = app_timer_create(&m_bsp_button_tmr,APP_TIMER_MODE_SINGLE_SHOT,button_timer_handler);}}
#elif (BUTTONS_NUMBER > 0) && (defined BSP_SIMPLE)bsp_board_init(type);
#endif // (BUTTONS_NUMBER > 0) && !(defined BSP_SIMPLE)#if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)if (type & BSP_INIT_LEDS){//handle LEDs only. Buttons are already handled.bsp_board_init(BSP_INIT_LEDS);// timers module must be already initialized!if (err_code == NRF_SUCCESS){err_code =app_timer_create(&m_bsp_leds_tmr, APP_TIMER_MODE_SINGLE_SHOT, leds_timer_handler);}if (err_code == NRF_SUCCESS){err_code =app_timer_create(&m_bsp_alert_tmr, APP_TIMER_MODE_REPEATED, alert_timer_handler);}}
#endif // LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)return err_code;
}

先看type用了位操作,来指示bsp初始化的操作方式,根据在boards.h文件里的定义其实就是LED和BUTTON,当然,后续可以在这个基础上扩展自己的板级硬件和初始化要求。 比如显示,比如其他接口等。

/**@defgroup BSP_BOARD_INIT_FLAGS Board initialization flags.* @{ */
#define BSP_INIT_NONE    0        /**< No initialization of LEDs or buttons (@ref bsp_board_init).*/
#define BSP_INIT_LEDS    (1 << 0) /**< Enable LEDs during initialization (@ref bsp_board_init).*/
#define BSP_INIT_BUTTONS (1 << 1) /**< Enable buttons during initialization (@ref bsp_board_init).*/
/**@} */

这个初始化里直接通过m_indication_type     = type; 把type丢给了m_indication_type ,那我们来看看m_indication_type发挥了什么作用,依然是在bsp.c 里,全文搜索

uint32_t bsp_indication_set(bsp_indication_t indicate)
{uint32_t err_code = NRF_SUCCESS;#if LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)if (m_indication_type & BSP_INIT_LEDS){err_code = bsp_led_indication(indicate);}#endif // LEDS_NUMBER > 0 && !(defined BSP_SIMPLE)return err_code;
}

这里提示就是依据m_indication_type说白了来判断板子上的LED配置情况,然后进行led指示灯的设置。

问题:这个设置在哪儿调用? 工作机制是怎样的? 

继续挖

先看调用的入口,查看得到

static void leds_timer_handler(void * p_context)
{UNUSED_PARAMETER(p_context);if (m_indication_type & BSP_INIT_LEDS){UNUSED_VARIABLE(bsp_led_indication(m_stable_state));}
}

所以这个看起来是leds用到的timer就是用来调用指示灯的驱动,完成状态和灯控的关联,那么leds的timer在哪儿启动和指定handler的呢? 

原来就在bsp_init里

 app_timer_create(&m_bsp_leds_tmr, APP_TIMER_MODE_SINGLE_SHOT, leds_timer_handler); 这一句通过app_timer的机制创建了led控制用的timer, 那么SIGLE_SHOT和REPEATED有什么区别? 为什么这里led控制用的是single shot呢? 

先放一放,看看指示灯状态切换的控制逻辑

static uint32_t bsp_led_indication(bsp_indication_t indicate)
{uint32_t err_code   = NRF_SUCCESS;uint32_t next_delay = 0;if (m_leds_clear){m_leds_clear = false;leds_off();}switch (indicate){case BSP_INDICATE_IDLE:leds_off();err_code       = app_timer_stop(m_bsp_leds_tmr);m_stable_state = indicate;break;case BSP_INDICATE_SCANNING:case BSP_INDICATE_ADVERTISING:// in advertising blink LED_0if (bsp_board_led_state_get(BSP_LED_INDICATE_INDICATE_ADVERTISING)){bsp_board_led_off(BSP_LED_INDICATE_INDICATE_ADVERTISING);next_delay = indicate ==BSP_INDICATE_ADVERTISING ? ADVERTISING_LED_OFF_INTERVAL :ADVERTISING_SLOW_LED_OFF_INTERVAL;}else{bsp_board_led_on(BSP_LED_INDICATE_INDICATE_ADVERTISING);next_delay = indicate ==BSP_INDICATE_ADVERTISING ? ADVERTISING_LED_ON_INTERVAL :ADVERTISING_SLOW_LED_ON_INTERVAL;}m_stable_state = indicate;err_code       = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(next_delay), NULL);break;case BSP_INDICATE_ADVERTISING_WHITELIST:// in advertising quickly blink LED_0if (bsp_board_led_state_get(BSP_LED_INDICATE_ADVERTISING_WHITELIST)){bsp_board_led_off(BSP_LED_INDICATE_ADVERTISING_WHITELIST);next_delay = indicate ==BSP_INDICATE_ADVERTISING_WHITELIST ?ADVERTISING_WHITELIST_LED_OFF_INTERVAL :ADVERTISING_SLOW_LED_OFF_INTERVAL;}else{bsp_board_led_on(BSP_LED_INDICATE_ADVERTISING_WHITELIST);next_delay = indicate ==BSP_INDICATE_ADVERTISING_WHITELIST ?ADVERTISING_WHITELIST_LED_ON_INTERVAL :ADVERTISING_SLOW_LED_ON_INTERVAL;}m_stable_state = indicate;err_code       = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(next_delay), NULL);break;case BSP_INDICATE_ADVERTISING_SLOW:// in advertising slowly blink LED_0if (bsp_board_led_state_get(BSP_LED_INDICATE_ADVERTISING_SLOW)){bsp_board_led_off(BSP_LED_INDICATE_ADVERTISING_SLOW);next_delay = indicate ==BSP_INDICATE_ADVERTISING_SLOW ? ADVERTISING_SLOW_LED_OFF_INTERVAL :ADVERTISING_SLOW_LED_OFF_INTERVAL;}else{bsp_board_led_on(BSP_LED_INDICATE_ADVERTISING_SLOW);next_delay = indicate ==BSP_INDICATE_ADVERTISING_SLOW ? ADVERTISING_SLOW_LED_ON_INTERVAL :ADVERTISING_SLOW_LED_ON_INTERVAL;}m_stable_state = indicate;err_code       = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(next_delay), NULL);break;case BSP_INDICATE_ADVERTISING_DIRECTED:// in advertising very quickly blink LED_0if (bsp_board_led_state_get(BSP_LED_INDICATE_ADVERTISING_DIRECTED)){bsp_board_led_off(BSP_LED_INDICATE_ADVERTISING_DIRECTED);next_delay = indicate ==BSP_INDICATE_ADVERTISING_DIRECTED ?ADVERTISING_DIRECTED_LED_OFF_INTERVAL :ADVERTISING_SLOW_LED_OFF_INTERVAL;}else{bsp_board_led_on(BSP_LED_INDICATE_ADVERTISING_DIRECTED);next_delay = indicate ==BSP_INDICATE_ADVERTISING_DIRECTED ?ADVERTISING_DIRECTED_LED_ON_INTERVAL :ADVERTISING_SLOW_LED_ON_INTERVAL;}m_stable_state = indicate;err_code       = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(next_delay), NULL);break;case BSP_INDICATE_BONDING:// in bonding fast blink LED_0bsp_board_led_invert(BSP_LED_INDICATE_BONDING);m_stable_state = indicate;err_code       =app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(BONDING_INTERVAL), NULL);break;case BSP_INDICATE_CONNECTED:bsp_board_led_on(BSP_LED_INDICATE_CONNECTED);m_stable_state = indicate;break;case BSP_INDICATE_SENT_OK:// when sending shortly invert LED_1m_leds_clear = true;bsp_board_led_invert(BSP_LED_INDICATE_SENT_OK);err_code = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(SENT_OK_INTERVAL), NULL);break;case BSP_INDICATE_SEND_ERROR:// on receving error invert LED_1 for long timem_leds_clear = true;bsp_board_led_invert(BSP_LED_INDICATE_SEND_ERROR);err_code = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(SEND_ERROR_INTERVAL), NULL);break;case BSP_INDICATE_RCV_OK:// when receving shortly invert LED_1m_leds_clear = true;bsp_board_led_invert(BSP_LED_INDICATE_RCV_OK);err_code = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(RCV_OK_INTERVAL), NULL);break;case BSP_INDICATE_RCV_ERROR:// on receving error invert LED_1 for long timem_leds_clear = true;bsp_board_led_invert(BSP_LED_INDICATE_RCV_ERROR);err_code = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(RCV_ERROR_INTERVAL), NULL);break;case BSP_INDICATE_FATAL_ERROR:// on fatal error turn on all ledsbsp_board_leds_on();m_stable_state = indicate;break;case BSP_INDICATE_ALERT_0:case BSP_INDICATE_ALERT_1:case BSP_INDICATE_ALERT_2:case BSP_INDICATE_ALERT_3:case BSP_INDICATE_ALERT_OFF:err_code   = app_timer_stop(m_bsp_alert_tmr);next_delay = (uint32_t)BSP_INDICATE_ALERT_OFF - (uint32_t)indicate;// a little trick to find out that if it did not fall through ALERT_OFFif (next_delay && (err_code == NRF_SUCCESS)){if (next_delay > 1){err_code = app_timer_start(m_bsp_alert_tmr,APP_TIMER_TICKS(((uint16_t)next_delay * ALERT_INTERVAL)),NULL);}bsp_board_led_on(BSP_LED_ALERT);m_alert_on = true;}else{bsp_board_led_off(BSP_LED_ALERT);m_alert_on = false;}break;case BSP_INDICATE_USER_STATE_OFF:leds_off();m_stable_state = indicate;break;case BSP_INDICATE_USER_STATE_0:leds_off();bsp_board_led_on(BSP_LED_INDICATE_USER_LED1);m_stable_state = indicate;break;case BSP_INDICATE_USER_STATE_1:leds_off();bsp_board_led_on(BSP_LED_INDICATE_USER_LED2);m_stable_state = indicate;break;case BSP_INDICATE_USER_STATE_2:leds_off();bsp_board_led_on(BSP_LED_INDICATE_USER_LED1);bsp_board_led_on(BSP_LED_INDICATE_USER_LED2);m_stable_state = indicate;break;case BSP_INDICATE_USER_STATE_3:case BSP_INDICATE_USER_STATE_ON:bsp_board_leds_on();m_stable_state = indicate;break;default:break;}return err_code;
}

基本上是个状态机,根据状态决定哪些灯要点亮 ,控制灯清楚了,可是控制闪亮的时间呢? 控制灯的对应关系在bsp_config.h文件里,包括了interval,但是interval是怎么控制间隔的呢? 

 

#define ADVERTISING_LED_ON_INTERVAL            200
#define ADVERTISING_LED_OFF_INTERVAL           1800#define ADVERTISING_DIRECTED_LED_ON_INTERVAL   200
#define ADVERTISING_DIRECTED_LED_OFF_INTERVAL  200#define ADVERTISING_WHITELIST_LED_ON_INTERVAL  200
#define ADVERTISING_WHITELIST_LED_OFF_INTERVAL 800#define ADVERTISING_SLOW_LED_ON_INTERVAL       400
#define ADVERTISING_SLOW_LED_OFF_INTERVAL      4000#define BONDING_INTERVAL                       100#define SENT_OK_INTERVAL                       100
#define SEND_ERROR_INTERVAL                    500#define RCV_OK_INTERVAL                        100
#define RCV_ERROR_INTERVAL                     500#define ALERT_INTERVAL                         200#define BSP_LED_INDICATE_SENT_OK               BSP_BOARD_LED_1
#define BSP_LED_INDICATE_SEND_ERROR            BSP_BOARD_LED_1
#define BSP_LED_INDICATE_RCV_OK                BSP_BOARD_LED_1
#define BSP_LED_INDICATE_RCV_ERROR             BSP_BOARD_LED_1
#define BSP_LED_INDICATE_CONNECTED             BSP_BOARD_LED_0
#define BSP_LED_INDICATE_BONDING               BSP_BOARD_LED_0
#define BSP_LED_INDICATE_ADVERTISING_DIRECTED  BSP_BOARD_LED_0
#define BSP_LED_INDICATE_ADVERTISING_SLOW      BSP_BOARD_LED_0
#define BSP_LED_INDICATE_ADVERTISING_WHITELIST BSP_BOARD_LED_0
#define BSP_LED_INDICATE_INDICATE_ADVERTISING  BSP_BOARD_LED_0#define BSP_LED_INDICATE_USER_LED1            BSP_BOARD_LED_0
#define BSP_LED_INDICATE_USER_LED2            BSP_BOARD_LED_1
#define BSP_LED_INDICATE_USER_LED3            BSP_BOARD_LED_2
#define BSP_LED_INDICATE_USER_LED4            BSP_BOARD_LED_3#define BSP_LED_ALERT                         BSP_BOARD_LED_2

 以其中一个状态灯控制的为例: 

case BSP_INDICATE_ADVERTISING:// in advertising blink LED_0if (bsp_board_led_state_get(BSP_LED_INDICATE_INDICATE_ADVERTISING)){bsp_board_led_off(BSP_LED_INDICATE_INDICATE_ADVERTISING);next_delay = indicate ==BSP_INDICATE_ADVERTISING ? ADVERTISING_LED_OFF_INTERVAL :ADVERTISING_SLOW_LED_OFF_INTERVAL;}else{bsp_board_led_on(BSP_LED_INDICATE_INDICATE_ADVERTISING);next_delay = indicate ==BSP_INDICATE_ADVERTISING ? ADVERTISING_LED_ON_INTERVAL :ADVERTISING_SLOW_LED_ON_INTERVAL;}m_stable_state = indicate;err_code       = app_timer_start(m_bsp_leds_tmr, APP_TIMER_TICKS(next_delay), NULL);break;

如果亮灯的,就灭掉,同时设置next_delay参数(下一个off动作的延时)

如果灭的,就点亮,同时设置next_delay参数(下一个on动作的延时)

启动timer,间隔对应的interval作为tick计时依据。有一句 m_stable_state = indicate;确保进来入口之后还来到这个处理分支。

回过头看问题,为什么用ONSHOT模式来启动timer,就是因为这种任务是进去之后再设定下次启动的间隙,而不是重复进入。 

另一条线是处理按键button的操作,从逻辑上来说,要做两个动作:

1) 将button按下和系统标准事件绑定

2)处理事件的操作

main.c里的bsp_evt_handler就是处理事件操作

void bsp_evt_handler(bsp_event_t evt)
{uint32_t err_code;switch (evt){case BSP_EVENT_KEY_0:if (actual_state != BSP_INDICATE_FIRST)actual_state--;elseactual_state = BSP_INDICATE_LAST;break;case BSP_EVENT_KEY_1:if (actual_state != BSP_INDICATE_LAST)actual_state++;elseactual_state = BSP_INDICATE_FIRST;break;default:return; // no implementation needed}err_code = bsp_indication_set(actual_state);NRF_LOG_INFO("%s", (uint32_t)indications_list[actual_state]);APP_ERROR_CHECK(err_code);
}

那么,按键怎么和事件关联的呢? 其实是在上面的bsp_init里有一半没讲完,就是除了初始化led外,对button的初始化

显示定义callback绑定入口,就是上面的evt_handler

m_registered_callback = callback;

这个类型定义

static bsp_event_callback_t   m_registered_callback         = NULL;

这个明显是个callback句柄的类型定义

typedef void (* bsp_event_callback_t)(bsp_event_t);

其实就是针对枚举句柄的指针调用

typedef enum
{BSP_EVENT_NOTHING = 0,                  /**< Assign this event to an action to prevent the action from generating an event (disable the action). */BSP_EVENT_DEFAULT,                      /**< Assign this event to an action to assign the default event to the action. */BSP_EVENT_CLEAR_BONDING_DATA,           /**< Persistent bonding data should be erased. */BSP_EVENT_CLEAR_ALERT,                  /**< An alert should be cleared. */BSP_EVENT_DISCONNECT,                   /**< A link should be disconnected. */BSP_EVENT_ADVERTISING_START,            /**< The device should start advertising. */BSP_EVENT_ADVERTISING_STOP,             /**< The device should stop advertising. */BSP_EVENT_WHITELIST_OFF,                /**< The device should remove its advertising whitelist. */BSP_EVENT_BOND,                         /**< The device should bond to the currently connected peer. */BSP_EVENT_RESET,                        /**< The device should reset. */BSP_EVENT_SLEEP,                        /**< The device should enter sleep mode. */BSP_EVENT_WAKEUP,                       /**< The device should wake up from sleep mode. */BSP_EVENT_SYSOFF,                       /**< The device should enter system off mode (without wakeup). */BSP_EVENT_DFU,                          /**< The device should enter DFU mode. */BSP_EVENT_KEY_0,                        /**< Default event of the push action of BSP_BUTTON_0 (only if this button is present). */BSP_EVENT_KEY_1,                        /**< Default event of the push action of BSP_BUTTON_1 (only if this button is present). */BSP_EVENT_KEY_2,                        /**< Default event of the push action of BSP_BUTTON_2 (only if this button is present). */BSP_EVENT_KEY_3,                        /**< Default event of the push action of BSP_BUTTON_3 (only if this button is present). */BSP_EVENT_KEY_4,                        /**< Default event of the push action of BSP_BUTTON_4 (only if this button is present). */BSP_EVENT_KEY_5,                        /**< Default event of the push action of BSP_BUTTON_5 (only if this button is present). */BSP_EVENT_KEY_6,                        /**< Default event of the push action of BSP_BUTTON_6 (only if this button is present). */BSP_EVENT_KEY_7,                        /**< Default event of the push action of BSP_BUTTON_7 (only if this button is present). */BSP_EVENT_KEY_LAST = BSP_EVENT_KEY_7,
} bsp_event_t;

bsp_init操作里和按键设置相关的初始化包括三个动作: 

 

    if (type & BSP_INIT_BUTTONS){uint32_t num;for (num = 0; ((num < BUTTONS_NUMBER) && (err_code == NRF_SUCCESS)); num++){err_code = bsp_event_to_button_action_assign(num, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_DEFAULT);}if (err_code == NRF_SUCCESS){err_code = app_button_init((app_button_cfg_t *)app_buttons,BUTTONS_NUMBER,APP_TIMER_TICKS(50));}if (err_code == NRF_SUCCESS){err_code = app_button_enable();}if (err_code == NRF_SUCCESS){err_code = app_timer_create(&m_bsp_button_tmr,APP_TIMER_MODE_SINGLE_SHOT,button_timer_handler);}}

1)事件和动作关联bsp_event_to_button_action_assign(num, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_DEFAULT);

2) 按键应用初始化app_button_init((app_button_cfg_t *)app_buttons,  BUTTONS_NUMBER,   APP_TIMER_TICKS(50));

3)创建timer,app_timer_create(&m_bsp_button_tmr,
APP_TIMER_MODE_SINGLE_SHOT,
button_timer_handler);

一项项来看看;

第一项, 动作分配是因为按键有三个动作,按下,松开和长按,所以这句调用是把push动作和event进行了关联分配

uint32_t bsp_event_to_button_action_assign(uint32_t button, bsp_button_action_t action, bsp_event_t event)
{uint32_t err_code = NRF_SUCCESS;#if BUTTONS_NUMBER > 0if (button < BUTTONS_NUMBER){if (event == BSP_EVENT_DEFAULT){// Setting default action: BSP_EVENT_KEY_x for PUSH actions, BSP_EVENT_NOTHING for RELEASE and LONG_PUSH actions.event = (action == BSP_BUTTON_ACTION_PUSH) ? (bsp_event_t)(BSP_EVENT_KEY_0 + button) : BSP_EVENT_NOTHING;}switch (action){case BSP_BUTTON_ACTION_PUSH:m_events_list[button].push_event = event;break;case BSP_BUTTON_ACTION_LONG_PUSH:m_events_list[button].long_push_event = event;break;case BSP_BUTTON_ACTION_RELEASE:m_events_list[button].release_event = event;break;default:err_code = NRF_ERROR_INVALID_PARAM;break;}}else{err_code = NRF_ERROR_INVALID_PARAM;}
#elseerr_code = NRF_ERROR_INVALID_PARAM;
#endif // BUTTONS_NUMBER > 0return err_code;
}#endif // BSP_SIMPLE

第二项的按键初始化其实是完成了对延时去抖的处理

uint32_t app_button_init(app_button_cfg_t const *       p_buttons,uint8_t                        button_count,uint32_t                       detection_delay)
{uint32_t err_code;if (detection_delay < 2*APP_TIMER_MIN_TIMEOUT_TICKS){return NRF_ERROR_INVALID_PARAM;}if (!nrf_drv_gpiote_is_init()){err_code = nrf_drv_gpiote_init();VERIFY_SUCCESS(err_code);}/* Save configuration. */mp_buttons          = p_buttons;m_button_count      = button_count;m_detection_delay   = detection_delay;memset(m_pin_states, 0, sizeof(m_pin_states));m_pin_active = 0;while (button_count--){app_button_cfg_t const * p_btn = &p_buttons[button_count];#if defined(BUTTON_HIGH_ACCURACY_ENABLED) && (BUTTON_HIGH_ACCURACY_ENABLED == 1)nrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(p_btn->hi_accuracy);
#elsenrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
#endifconfig.pull = p_btn->pull_cfg;err_code = nrf_drv_gpiote_in_init(p_btn->pin_no, &config, gpiote_event_handler);VERIFY_SUCCESS(err_code);}/* Create polling timer. */return app_timer_create(&m_detection_delay_timer_id,APP_TIMER_MODE_SINGLE_SHOT,detection_delay_timeout_handler);
}

第三项的timer处理其实是完成了actions的区分和处理

static void bsp_button_event_handler(uint8_t pin_no, uint8_t button_action)
{bsp_event_t        event  = BSP_EVENT_NOTHING;uint32_t           button = 0;uint32_t           err_code;static uint8_t     current_long_push_pin_no;              /**< Pin number of a currently pushed button, that could become a long push if held long enough. */static bsp_event_t release_event_at_push[BUTTONS_NUMBER]; /**< Array of what the release event of each button was last time it was pushed, so that no release event is sent if the event was bound after the push of the button. */button = bsp_board_pin_to_button_idx(pin_no);if (button < BUTTONS_NUMBER){switch (button_action){case APP_BUTTON_PUSH:event = m_events_list[button].push_event;if (m_events_list[button].long_push_event != BSP_EVENT_NOTHING){err_code = app_timer_start(m_bsp_button_tmr, APP_TIMER_TICKS(BSP_LONG_PUSH_TIMEOUT_MS), (void*)&current_long_push_pin_no);if (err_code == NRF_SUCCESS){current_long_push_pin_no = pin_no;}}release_event_at_push[button] = m_events_list[button].release_event;break;case APP_BUTTON_RELEASE:(void)app_timer_stop(m_bsp_button_tmr);if (release_event_at_push[button] == m_events_list[button].release_event){event = m_events_list[button].release_event;}break;case BSP_BUTTON_ACTION_LONG_PUSH:event = m_events_list[button].long_push_event;}}if ((event != BSP_EVENT_NOTHING) && (m_registered_callback != NULL)){m_registered_callback(event);}
}

至此,解析完毕。 

例程的功能,就是在按键按下后在state之间切换,并且启动标准的state对应的闪灯程序,可以作为经典的状态切换例程来模仿和学习。

 

 

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 磁盘管理与文件系统-----------------终极小秘籍----------------------

    文章目录一、磁盘基础1.1 磁盘结构1.2 MBR与磁盘分区表示1.3 磁盘分区结构二、检测并确认新硬盘2.1 检测并确认新硬盘2.2 查看硬盘相关信息三、创建文件系统3.1 文件系统类型3.2 创建文件系统四、挂载、卸载文件系统4.1 管理文件系统4.2 U盘挂载到系统中 一、磁盘基础 1.1 磁盘…...

    2024/4/25 9:40:42
  2. 【06】processing-交互(中文)

    互动性Casey Reas 和 Ben Fry屏幕在我们的身体和计算机内部的电路和电之间形成了一座桥梁。我们通过触摸板、轨迹球和操纵杆等多种设备控制屏幕上的元素,但键盘和鼠标仍然是台式计算机最常用的输入设备。计算机鼠标可以追溯到20世纪60年代末,当时道格拉斯恩格尔巴特将该设备作…...

    2024/4/15 18:02:25
  3. python面试题 更新中

    python面试题 日常更新1.设置Python模块的搜索路径有几种方式 1.设置Python模块的搜索路径有几种方式设置PYTHONPATH环境变量添加. pth文件 在python的安装路径下的/lib/python版本号/site-package/ 下创建 XXX.pth ,打开XXX.pth添加需要导入的路径 通过sys . path设置路径 如…...

    2024/4/27 13:22:55
  4. 模型的评估与选择

    2.1 经验误差与过拟合 错误率与精度 错误率E=a/m,a为分类错误的样本个数,m为测试样本总数。 精度=1-错误率 学习器在训练集上的误差称为“训练误差”或“经验误差”,在新样本上的误差称为“泛化误差”。 过拟合:学习器把训练样本学的“太好”了的时候,很可能已经把训练样本…...

    2024/4/20 8:36:22
  5. 排列的置换运算

    1.定义 给定定两个排列P=p1,p2,...,pnP={p_1,p_2,...,p_n}P=p1​,p2​,...,pn​,Q=q1,q2,...,qnQ={q_1,q_2,...,q_n}Q=q1​,q2​,...,qn​。 排列QQQ关于排列PPP进行置换运算得到的新排列为 Ans=Q∗P=PQ1,PQ2,...,PQnAns=Q*P={P_{Q_1},P_{Q_2},...,P_{Q_n}}Ans=Q∗P=PQ1​​,P…...

    2024/4/30 4:12:20
  6. socket理论

    对TCP/IP、UDP、Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵。那么我想问: 1. 什么是TCP/IP、UDP? 2. Socket在哪里呢? 3. Socket是什么呢? 4. 你会使用它们吗?什么是TCP/IP、UDP?TCP/IP(Transmissio…...

    2024/4/20 10:10:50
  7. Spring Cloud Alibaba - Zipkin 链路追踪可视化 (介绍 / 简单使用 / 持久化)

    Spring Cloud Alibaba - Zipkin 链路追踪可视化回溯ZipKin介绍ZipKin使用ZipKin服务端安装ZipKin客户端集成ZipKin数据持久化ZipKin数据持久化到MySqlZipKin数据持久化到Elasticsearch 回溯 在上一篇博文中 Spring Cloud Alibaba - Sleuth 链路追踪技术,讲述了如何利用 Sleuth…...

    2024/4/25 15:53:21
  8. 深入浅出的讲解傅里叶变换(真正的通俗易懂)

    我保证这篇文章和你以前看过的所有文章都不同,这是 2012 年还在果壳的时候写的,但是当时没有来得及写完就出国了……于是拖了两年,嗯,我是拖延症患者……这篇文章的核心思想就是:要让读者在不看任何数学公式的情况下理解傅里叶分析。傅里叶分析不仅仅是一个数学工具,更是…...

    2024/5/3 23:11:01
  9. Canvas绘制大时钟

    创建canvas标签 <canvas width="500" height="500" class="canvas"></canvas> 绘制圆刻度和时间 arc(x, y, r, start, stop) x, y, r : 分别是圆的圆心坐标和半径。 start:起始角,以弧度计 stop : 结束角, 以弧度计 角度和弧度的…...

    2024/4/30 3:11:10
  10. Sqlibs-Less46-53-order by注入

    46.less46-ORDER BY-Error-Numeric 46.1、注入分析 从本关开始,我们开始学习order by 相关注入的知识。本关的sql语句为 sql="SELECT ∗ FROM users ORDER BY id";尝试?sort=1 desc或者asc,显示结果不同,则表明可以注入。(升序or降序排列) 从上述的sql语句中我…...

    2024/4/13 8:27:00
  11. 【JAVA】三角形最小路径和——力扣每日一题(二)(2020.07.14)

    目录题目:120. 三角形最小路径和前言一、自底向上方法1:动态规划(DP)方法2:递归(晚点补充)二、自顶向下如果你从本文中学习到丝毫知识,那么请您点点关注、点赞、评论和收藏 大家好,我是爱做梦的鱼,我是东北大学大数据实验班大三的小菜鸡,非常渴望优秀,羡慕优秀的人…...

    2024/5/3 20:04:54
  12. mysql8.0以上版本:忘记密码怎么办——免密重置!(不踩坑的完整流程)

    创作日志:突然要用mysql做项目,一年没用mysql密码早忘了,以前都存在手机备忘录上,但那手机现在开不了机了,头都要秃了,找了各种办法,前面一直被一些已经过时的办法坑,比如 mysqld --skip-grant-tables 命令,根本不适用于mysql8.0的版本,后来成功登进去了又迟迟修改不…...

    2024/4/12 2:58:06
  13. 数据结构----树的基本概念

    文章目录一、基本术语【1】度的分类【2】兄弟【3】节点的分类【4】节点的高度,深度和层次【5】有序树和无序树【6】路径和路径长度【7】森林二、树的性质三、二叉树的概念 一、基本术语 【1】度的分类节点的度:树中一个节点的孩子个数 树的度:树中节点的最大度数【2】兄弟 概…...

    2024/4/12 11:45:42
  14. [GXYCTF2019]luck_guy

    http://0kam1.top/index.php/2020/07/14/27/...

    2024/4/12 9:05:51
  15. 音视频基础(25)H264编码实战

    文章目录音视频基础(25)H264编码实战 音视频基础(25)H264编码实战...

    2024/4/12 8:44:01
  16. 【PAT Basic Level】1084 外观数列

    目录题目分析代码 专栏:PAT乙级刷题笔记 题目外观数列是指具有以下特点的整数序列: d, d1, d111, d113, d11231, d112213111, … 它从不等于 1 的数字 d 开始,序列的第 n+1 项是对第 n 项的描述。比如第 2 项表示第 1 项有 1 个 d,所以就是 d1;第 2 项是 1 个 d(对应 d1)…...

    2024/4/26 19:29:33
  17. Java秒杀系统方案优化 高性能高并发实战,学习手记(六)

    大家好,我是方圆 让我们康康缓存优化是怎么回事?目录1. 页面缓存优化1.1 未经优化之前的代码1.2 优化产生的改变2. 对象缓存与缓存更新2.1 对象缓存2.2 缓存更新 1. 页面缓存优化 1.1 未经优化之前的代码@RequestMapping("/to_list")public String toList(Model mo…...

    2024/4/22 1:35:09
  18. xxx

    Oh_My_Ada 2020-07-13 22:47:00 ①首先我把Ubuntu内部的源都改成了国内阿里云镜像 Oh_My_Ada 2020-07-13 22:47:18 虽然我不知道这一步有没有影响,反正下载速度是挺快的 Oh_My_Ada 2020-07-13 22:47:28 参考资料https://www.cnblogs.com/zhishifenzi/p/9559259.html Oh_My_Ada…...

    2024/4/26 0:49:13
  19. xhtml和html的区别错误:

    xhtml是更严格的html 主要区别: 1.XHTML 元素必须被正确地嵌套。错误:<p><span>Hello XHTML</p></span>正确:<p><span>Hello XHTML</span></p>2.XHTML 元素必须被关闭。错误:<p>Hello XHTML正确:<p>Hello XH…...

    2024/4/22 2:04:04
  20. SpringMVC数据流程绑定分析

    提问:前端表单传递过来的数据为什么能够自动的封装成实体类的对象?为什么能够进行自动的类型转换?数据绑定流程SpringMVC框架将ServletRequest对象及目标方法的入参实例传递给WebDataBinderFactory实例,以便创建DataBinder对象。 DataBinder调用装配在SpringMVC上下文的Con…...

    2024/4/29 9:33:28

最新文章

  1. linux进入单用户模式指引

    文章目录 引言I 通过GRUB进入单用户模式1.1 倒计时界面的操作1.2 GRUB1.3 内核参数编辑界面1.4 更多内核参数编辑界面II 预备知识:Linux用户模式引言 应用场景: root密码重置: 用passwd命令修改root修复登录相关的配置:/etc/pam.d/login 和 /etc/pam.d/sshd 案例:Centos6进…...

    2024/5/4 0:05:18
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. MySQL 底层数据结构 聚簇索引以及二级索引 Explain的使用

    数据结构 我们知道MySQL的存储引擎Innodb默认底层是使用B树的变种来存储数据的 下面我们来复习一下B树存储 B树存储 哈希存储的区别 哈希存储,只能使用等值查询 B树与B树存储 我们知道B树实际上就是B树的变种 那么为啥使用B树而不是使用B树呢? 我们知道效率的高低主要取决于…...

    2024/5/2 2:42:20
  4. OpenHarmony实战:Combo解决方案之ASR芯片移植案例

    本方案基于 OpenHarmony LiteOS-M 内核&#xff0c;使用 ASR582X 芯片的 DEV.WIFI.A 开发板进行开发移植。作为典型的 IOT Combo&#xff08;Wi-FiBLE&#xff09;解决方案&#xff0c;本文章介绍 ASR582X 的适配过程。 编译移植 目录规划 本方案的目录结构使用 Board 和 So…...

    2024/5/1 13:53:04
  5. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/5/3 11:50:27
  6. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/5/2 16:04:58
  7. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/5/2 23:55:17
  8. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/5/3 16:00:51
  9. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/5/3 11:10:49
  10. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/5/3 21:22:01
  11. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/5/3 23:17:01
  12. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/5/2 23:47:43
  13. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/5/3 13:26:06
  14. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/5/3 1:55:15
  15. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/5/2 9:47:28
  16. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/5/3 16:23:03
  17. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/5/3 1:55:09
  18. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/5/2 8:37:00
  19. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/5/3 14:57:24
  20. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/5/2 9:47:25
  21. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/5/2 23:47:16
  22. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/5/3 22:03:11
  23. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/5/3 7:43:42
  24. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/5/3 1:54:59
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57