【低功耗蓝牙】⑤ 蓝牙HID协议

【低功耗蓝牙】⑤ 蓝牙HID协议摘要本文章主要介绍了蓝牙 HID 协议的实现方法 基于 ESP32 平台实现了蓝牙键盘 蓝牙鼠标 蓝牙自拍杆和蓝牙游戏手柄等设备 是初学者学习 BLEHID 协议很好的参考文章 HID 设备 HID HumanInterfa 人体学接口设备 是生活中常见的输入设备 比如键盘鼠标游戏手柄等等 早期的 HID 是设备大部分都是通过 USB 接口来实现 蓝牙技术出现后 通过蓝牙作为传输层 实现了无线 HID 设备 通过低功耗蓝牙实现的 HID 功能一般简称为 HOGP HIDoverGattP

摘要

本文章主要介绍了蓝牙HID协议的实现方法,基于ESP32平台实现了蓝牙键盘,蓝牙鼠标,蓝牙自拍杆和蓝牙游戏手柄等设备,是初学者学习BLE HID协议很好的参考文章。

HID设备

常见HID设备

HID(Human Interface Device)人体学接口设备,是生活中常见的输入设备,比如键盘鼠标游戏手柄等等。早期的HID是设备大部分都是通过USB接口来实现,蓝牙技术出现后,通过蓝牙作为传输层,实现了无线HID设备。通过低功耗蓝牙实现的HID功能一般简称为HOGP(HID over Gatt Profile)。

蓝牙HID设备的实现

任何低功耗蓝牙模块都可以通过软件开发实现HID功能,一个蓝牙模块要实现HID的功能,一般需满足如下两个条件:

②、在GATT中实现HID要求的服务和特性。

蓝牙HIDS UUID

0x1812是HID Service的UUID,必须要使用该UUID实现服务。

0x2A4A是HID Information 的特性UUID,主要功能是展示HID的信息,其值为4个字节:
前两个字节是HID版本,一般填入0x01,0x01,表示版本号为1.1
第三个字节是Country Code,一般填入0x00
第四个字节是HID Flags,一般填入0x02,表示Normally Connectable。






0x2A4B是Report Map的特性UUID,主要功能是描述HID设备与HID主机数据交互的方式,即二者之间所发送的数据每一位的含义。

0x2A4C是Control Point的特性UUID,该特性一定要可Write ,HID主机通过该特性告知HID设备主机的状态,比如电脑休眠后会告知蓝牙键盘也进入低功耗模式。

0x2A4D是HID设备与HID主机之间交互数据(Report)的特性UUID。
对于键盘设备,当某个按键按下时,HID设备发送数据到HID主机;当开关CapsLock,NumsLook和ScrollLook功能时,HID主机将相关指示灯的状态发送给HID键盘。所以键盘设备需要两个UUID为0x2A4D的特性,一个用于发送数据,另一个用于接收数据(使用UUID为0x2908的描述来区分)。
而对于鼠标,游戏手柄这种只发送数据给电脑的设备,只需要定义一个0x2A4D的特性用来发送数据就可以了(当然定义两个也不会出错)。




0x2A4E是协议模式的特性UUID,对于键盘和鼠标这两种设备,可能也会在电脑BIOS阶段使用,此阶段的计算机没有进入系统,难以支持复杂的设备。所以键盘鼠标就有两种模式,分别是Report模式和Boot模式,系统启动前使用的是Boot模式,HID设备与HID主机之间使用固定的数据格式进行交互。系统启动完成后,HID主机会通过该特性发数据给HID设备,通知HID设备切换成Report模式,在Report模式下,数据格式由 Report Map 决定。
该特性的数据值为0x00表示Boot模式,0x01表示Report模式。

在Boot模式下,Keyboard Input 的特性UUID是0x2A22,Output 的特性UUID是0x2A32;Mous Input 的特性UUID是0x2A33

本文章只讨论Report模式,暂不讨论Boot模式!

蓝牙键盘

下列代码基于ESP32芯片MicroPython固件(V1.16以上)给出了简单的蓝牙键盘案例:

from machine import Pin import ubluetooth #导入BLE功能模块 from bluetooth import UUID ble = ubluetooth.BLE() #创建BLE设备 ble.active(True) #打开BLE ble.config(gap_name="ESP Keyboard") ble.config(mtu=23) HIDS = ( # Service description: describes the service and how we communicate UUID(0x1812), # Human Interface Device ( (UUID(0x2A4A), ubluetooth.FLAG_READ), # HID information (UUID(0x2A4B), ubluetooth.FLAG_READ), # HID report map (UUID(0x2A4C), ubluetooth.FLAG_WRITE), # HID control point (UUID(0x2A4D), ubluetooth.FLAG_READ | ubluetooth.FLAG_NOTIFY, ((UUID(0x2908), 1),)), # HID report / reference (UUID(0x2A4D), ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE, ((UUID(0x2908), 1),)), # HID report / reference (UUID(0x2A4E), ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE), # HID protocol mode ), ) services = (HIDS,) handles = ble.gatts_register_services(services) KEYBOARD_REPORT = bytes([ # Report Description: describes what we communicate 0x05, 0x01, # USAGE_PAGE (Generic Desktop) 0x09, 0x06, # USAGE (Keyboard) 0xa1, 0x01, # COLLECTION (Application) 0x85, 0x01, # REPORT_ID (1) 0x75, 0x01, # Report Size (1) 0x95, 0x08, # Report Count (8) 0x05, 0x07, # Usage Page (Key Codes) 0x19, 0xE0, # Usage Minimum (224) 0x29, 0xE7, # Usage Maximum (231) 0x15, 0x00, # Logical Minimum (0) 0x25, 0x01, # Logical Maximum (1) 0x81, 0x02, # Input (Data, Variable, Absolute); Modifier byte 0x95, 0x01, # Report Count (1) 0x75, 0x08, # Report Size (8) 0x81, 0x01, # Input (Constant); Reserved byte 0x95, 0x05, # Report Count (5) 0x75, 0x01, # Report Size (1) 0x05, 0x08, # Usage Page (LEDs) 0x19, 0x01, # Usage Minimum (1) 0x29, 0x05, # Usage Maximum (5) 0x91, 0x02, # Output (Data, Variable, Absolute); LED report 0x95, 0x01, # Report Count (1) 0x75, 0x03, # Report Size (3) 0x91, 0x01, # Output (Constant); LED report padding 0x95, 0x06, # Report Count (6) 0x75, 0x08, # Report Size (8) 0x15, 0x00, # Logical Minimum (0) 0x25, 0x65, # Logical Maximum (101) 0x05, 0x07, # Usage Page (Key Codes) 0x19, 0x00, # Usage Minimum (0) 0x29, 0x65, # Usage Maximum (101) 0x81, 0x00, # Input (Data, Array); Key array (6 bytes) 0xc0 # END_COLLECTION ]) #设置BLE广播数据并开始广播 ble.gap_advertise(100, adv_data = b'\x02\x01\x05' + b'\x03\x03\x12\x18' #HID UUID + b'\x03\x19\xC1\x03' #设备外观为键盘 + b'\x0D\x09' + "ESP Keyboard".encode("UTF-8")) (h_info, h_map, _, h_repin, h_d1, h_repout, h_d2, h_model,) = handles[0] # Write service characteristics ble.gatts_write(h_info, b"\x01\x01\x00\x02") # HID info: ver=1.1, country=0, flags=normal ble.gatts_write(h_map, KEYBOARD_REPORT) # HID input report map ble.gatts_write(h_d1, b"\x01\x01") # HID reference: id=1, type=input ble.gatts_write(h_d2, b"\x01\x02") # HID reference: id=1, type=output ble.gatts_write(h_model, b"\x01") # HID Protocol Model: 0=Boot Model, 1=Report Model key = Pin(0,Pin.IN)#IO 0 用作按键 while True: if key.value() == 0: while key.value() == 0: pass ble.gatts_notify(0, h_repin, b'\x00\x00\x04\x00\x00\x00\x00\x00')#按键A按下 ble.gatts_notify(0, h_repin, b'\x00\x00\x00\x00\x00\x00\x00\x00')#按键A抬起 

上述代码实现了一个简单的蓝牙键盘,按下设备上IO0对应的按键,发送按键A到HID主机。
上述代码的ReportMap中定义了HID设备发给HID主机的数据为8个字节,定义如下图:

Keyboard Report Data
第一个字节是Modifier按键,相应的位为1表示对应的按键按下(GUI在Windows下是Win键);第二个字节保留,默认为零。第三到第八字节可表示六个按键,数据值为零表示无按键按下,按键对应的代码可搜索HID KeyCode,比如按键A对应的代码是0x04,按键B对应的代码是0x05,Enter键对应的代码是0x28

比如:

0x80,0x00,0x06,0x00,0x00,0x00,0x00,0x00 //表示同时按下Ctrl键和字母C键。 0x40,0x00,0x04,0x00,0x00,0x00,0x00,0x00 //表示同时按下Shift键和字母A键。 

需要注意的是,发送某个按键按下的数据后,需及时发送按键抬起的数据,否则系统会认为按键未抬起,从而触发长按操作。

蓝牙自拍杆

自拍杆是最近几年出现的产品,其实蓝牙自拍杆的本质就是一个超简易的蓝牙键盘。我们知道在手机拍照页面,音量调节按键可以触发快门拍照,蓝牙自拍杆本质上就是一个只能调节音量的蓝牙键盘。调节音量是键盘的高级功能,可通过如下代码试下:

from machine import Pin import ubluetooth #导入BLE功能模块 from bluetooth import UUID ble = ubluetooth.BLE() #创建BLE设备 ble.active(True) #打开BLE ble.config(gap_name="ESP Keyboard") ble.config(mtu=23) HIDS = ( # Service description: describes the service and how we communicate UUID(0x1812), # Human Interface Device ( (UUID(0x2A4A), ubluetooth.FLAG_READ), # HID information (UUID(0x2A4B), ubluetooth.FLAG_READ), # HID report map (UUID(0x2A4C), ubluetooth.FLAG_WRITE), # HID control point (UUID(0x2A4D), ubluetooth.FLAG_READ | ubluetooth.FLAG_NOTIFY, ((UUID(0x2908), 1),)), # HID report / reference (UUID(0x2A4D), ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE, ((UUID(0x2908), 1),)), # HID report / reference (UUID(0x2A4E), ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE), # HID protocol mode ), ) services = (HIDS,) handles = ble.gatts_register_services(services) MEDIA_REPORT = bytes([ # Report Description: describes what we communicate # Report ID 1: Advanced buttons 0x05, 0x0C, # Usage Page (Consumer) 0x09, 0x01, # Usage (Consumer Control) 0xA1, 0x01, # Collection (Application) 0x85, 0x01, # Report Id (1) 0x15, 0x00, # Logical minimum (0) 0x25, 0x01, # Logical maximum (1) 0x75, 0x01, # Report Size (1) 0x95, 0x01, # Report Count (1) 0x09, 0xCD, # Usage (Play/Pause) 0x81, 0x06, # Input (Data,Value,Relative,Bit Field) 0x0A, 0x83, 0x01, # Usage (AL Consumer Control Configuration) 0x81, 0x06, # Input (Data,Value,Relative,Bit Field) 0x09, 0xB5, # Usage (Scan Next Track) 0x81, 0x06, # Input (Data,Value,Relative,Bit Field) 0x09, 0xB6, # Usage (Scan Previous Track) 0x81, 0x06, # Input (Data,Value,Relative,Bit Field) 0x09, 0xEA, # Usage (Volume Down) 0x81, 0x06, # Input (Data,Value,Relative,Bit Field) 0x09, 0xE9, # Usage (Volume Up) 0x81, 0x06, # Input (Data,Value,Relative,Bit Field) 0x0A, 0x25, 0x02, # Usage (AC Forward) 0x81, 0x06, # Input (Data,Value,Relative,Bit Field) 0x0A, 0x24, 0x02, # Usage (AC Back) 0x81, 0x06, # Input (Data,Value,Relative,Bit Field) 0xC0 # End Collection ]) #设置BLE广播数据并开始广播 ble.gap_advertise(100, adv_data = b'\x02\x01\x05' + b'\x03\x03\x12\x18' #HID UUID + b'\x03\x19\xC1\x03' #设备外观为键盘 + b'\x0D\x09' + "ESP Keyboard".encode("UTF-8")) (h_info, h_map, _, h_repin, h_d1, h_repout, h_d2, h_model,) = handles[0] # Write service characteristics ble.gatts_write(h_info, b"\x01\x01\x00\x02") # HID info: ver=1.1, country=0, flags=normal ble.gatts_write(h_map, MEDIA_REPORT) # HID input report map ble.gatts_write(h_d1, b"\x01\x01") # HID reference: id=1, type=input ble.gatts_write(h_d2, b"\x01\x02") # HID reference: id=1, type=output ble.gatts_write(h_model, b"\x01") # HID Protocol Model: 0=Boot Model, 1=Report Model key = Pin(0,Pin.IN)#IO 0 用作按键 while True: if key.value() == 0: while key.value() == 0: pass ble.gatts_notify(0, h_repin, b'\x10')#音量- 按下 ble.gatts_notify(0, h_repin, b'\x00')#音量- 抬起 

上述代码试下了媒体控制的功能,按下设备上IO0对应的按键,执行音量-的动作。上述Report Map中定义了键盘的高级按键,媒体控制的功能,发送给HID主机的数据为一个字节,每一位定义如下:

Media Control 按键

0x10表示音量-,0x04表示下一曲。

蓝牙鼠标

下列代码给出了简单的蓝牙鼠标的示例代码:

from machine import Pin import ubluetooth #导入BLE功能模块 from bluetooth import UUID ble = ubluetooth.BLE() #创建BLE设备 ble.active(True) #打开BLE ble.config(gap_name="ESP Mouse") ble.config(mtu=23) HIDS = ( # Service description: describes the service and how we communicate UUID(0x1812), # Human Interface Device ( (UUID(0x2A4A), ubluetooth.FLAG_READ), # HID information (UUID(0x2A4B), ubluetooth.FLAG_READ), # HID report map (UUID(0x2A4C), ubluetooth.FLAG_WRITE), # HID control point (UUID(0x2A4D), ubluetooth.FLAG_READ | ubluetooth.FLAG_NOTIFY, ((UUID(0x2908), 1),)), # HID report / reference (UUID(0x2A4D), ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE, ((UUID(0x2908), 1),)), # HID report / reference (UUID(0x2A4E), ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE), # HID protocol mode ), ) services = (HIDS,) handles = ble.gatts_register_services(services) MOUSE_REPORT = bytes([ # Report Description: describes what we communicate 0x05, 0x01, # USAGE_PAGE (Generic Desktop) 0x09, 0x02, # USAGE (Mouse) 0xa1, 0x01, # COLLECTION (Application) 0x85, 0x01, # REPORT_ID (1) 0x09, 0x01, # USAGE (Pointer) 0xa1, 0x00, # COLLECTION (Physical) 0x05, 0x09, # Usage Page (Buttons) 0x19, 0x01, # Usage Minimum (1) 0x29, 0x03, # Usage Maximum (3) 0x15, 0x00, # Logical Minimum (0) 0x25, 0x01, # Logical Maximum (1) 0x95, 0x03, # Report Count (3) 0x75, 0x01, # Report Size (1) 0x81, 0x02, # Input(Data, Variable, Absolute); 3 button bits 0x95, 0x01, # Report Count(1) 0x75, 0x05, # Report Size(5) 0x81, 0x03, # Input(Constant); 5 bit padding 0x05, 0x01, # Usage Page (Generic Desktop) 0x09, 0x30, # Usage (X) 0x09, 0x31, # Usage (Y) 0x09, 0x38, # Usage (Wheel) 0x15, 0x81, # Logical Minimum (-127) 0x25, 0x7F, # Logical Maximum (127) 0x75, 0x08, # Report Size (8) 0x95, 0x03, # Report Count (3) 0x81, 0x06, # Input(Data, Variable, Relative); 3 position bytes (X,Y,Wheel) 0xc0, # END_COLLECTION 0xc0 # END_COLLECTION ]) #设置BLE广播数据并开始广播 ble.gap_advertise(100, adv_data = b'\x02\x01\x05' + b'\x03\x03\x12\x18' #HID UUID + b'\x03\x19\xC2\x03' #设备外观为鼠标 + b'\x0A\x09' + "ESP Mouse".encode("UTF-8")) (h_info, h_map, _, h_repin, h_d1, h_repout, h_d2, h_model,) = handles[0] # Write service characteristics ble.gatts_write(h_info, b"\x01\x01\x00\x02") # HID info: ver=1.1, country=0, flags=normal ble.gatts_write(h_map, MOUSE_REPORT) # HID input report map ble.gatts_write(h_d1, b"\x01\x01") # HID reference: id=1, type=input ble.gatts_write(h_d2, b"\x01\x02") # HID reference: id=1, type=output ble.gatts_write(h_model, b"\x01") # HID Protocol Model: 0=Boot Model, 1=Report Model key = Pin(0,Pin.IN)#IO 0 用作按键 while True: if key.value() == 0: while key.value() == 0: pass ble.gatts_notify(0, h_repin, b'\x00\x0A\xF6\x00')#X正方向和Y的负方向各移动10像素 ble.gatts_notify(0, h_repin, b'\x00\x00\x00\x00')# 

上述代码实现了简单的蓝牙鼠标的功能,按下设备上IO0对应的按键,鼠标指针将向右和向上各移动10个像素单位。上述代码中的Report Map定义了HID设备发给HID主机的数据为4个字节,每个字节含义如下:

Mouse Report

一个标准的鼠标上面有三个按键(左键右键中间键)一个滑轮和一个光标。上述数据中,第一个字节的第三位表示三个按键按下与否(具体如何对应未知),第二个字节表示鼠标指针在X方向的移动量,取值范围-127 ~ 127,第三字节表示鼠标指针在Y方向的移动量,取值范围是-127 ~ 127,第四个字节表示鼠标滑轮的滚动量,取值范围是-127 ~ 128。

比如:

0x01,0x00,0x00,0x00 表示鼠标上的某个按键按下。

0x00,0x09,0x09,0x00 表示鼠标指针向X正方向和Y正方向个移动9个像素单位。

0x00,0x00,0x00,0x01 表示鼠标滑轮滚动一格。

蓝牙游戏手柄

下列代码给出了简单的蓝牙游戏手柄案例:

from machine import Pin from time import sleep_ms import ubluetooth #导入BLE功能模块 from bluetooth import UUID import struct ble = ubluetooth.BLE() #创建BLE设备 ble.active(True) #打开BLE ble.config(gap_name="ESP Joystick") ble.config(mtu=23) HIDS = ( # Service description: describes the service and how we communicate UUID(0x1812), # Human Interface Device ( (UUID(0x2A4A), ubluetooth.FLAG_READ), # HID information (UUID(0x2A4B), ubluetooth.FLAG_READ), # HID report map (UUID(0x2A4C), ubluetooth.FLAG_WRITE), # HID control point (UUID(0x2A4D), ubluetooth.FLAG_READ | ubluetooth.FLAG_NOTIFY, ((UUID(0x2908), 1),)), # HID report / reference (UUID(0x2A4D), ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE, ((UUID(0x2908), 1),)), # HID report / reference (UUID(0x2A4E), ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE), # HID protocol mode ), ) services = (HIDS,) handles = ble.gatts_register_services(services) JOY_REPORT = bytes([ # Report Description: describes what we communicate 0x05, 0x01, # USAGE_PAGE (Generic Desktop) 0x09, 0x04, # USAGE (Joystick) 0xa1, 0x01, # COLLECTION (Application) 0x85, 0x01, # REPORT_ID (1) 0xa1, 0x00, # COLLECTION (Physical) 0x09, 0x30, # USAGE (X) 0x09, 0x31, # USAGE (Y) 0x15, 0x81, # LOGICAL_MINIMUM (-127) 0x25, 0x7f, # LOGICAL_MAXIMUM (127) 0x75, 0x08, # REPORT_SIZE (8) 0x95, 0x02, # REPORT_COUNT (2) 0x81, 0x02, # INPUT (Data,Var,Abs) 0x05, 0x09, # USAGE_PAGE (Button) 0x29, 0x08, # USAGE_MAXIMUM (Button 8) 0x19, 0x01, # USAGE_MINIMUM (Button 1) 0x95, 0x08, # REPORT_COUNT (8) 0x75, 0x01, # REPORT_SIZE (1) 0x25, 0x01, # LOGICAL_MAXIMUM (1) 0x15, 0x00, # LOGICAL_MINIMUM (0) 0x81, 0x02, # Input (Data, Variable, Absolute) 0xc0, # END_COLLECTION 0xc0 # END_COLLECTION ]) # Report Size (1) #设置BLE广播数据并开始广播 ble.gap_advertise(100, adv_data = b'\x02\x01\x05' + b'\x03\x03\x12\x18' #HID UUID + b'\x03\x19\xC3\x03' #设备外观为手柄 + b'\x0D\x09' + "ESP Joystick".encode("UTF-8")) (h_info, h_map, _, h_repin, h_d1, h_repout, h_d2, h_model,) = handles[0] # Write service characteristics ble.gatts_write(h_info, b"\x01\x01\x00\x02") # HID info: ver=1.1, country=0, flags=normal ble.gatts_write(h_map, JOY_REPORT) # HID input report map ble.gatts_write(h_d1, struct.pack(" 
    
    , 
    1 
    , 
    1 
    ) 
    ) 
    # HID reference: id=1, type=input ble 
    .gatts_write 
    (h_d2 
    , struct 
    .pack 
    ( 
    " 
      
      , 
      1 
      , 
      2 
      ) 
      ) 
      # HID reference: id=1, type=output ble 
      .gatts_write 
      (h_model 
      , 
      b"\x01" 
      ) 
      # HID Protocol Model: 0=Boot Model, 1=Report Model key 
      = Pin 
      ( 
      0 
      ,Pin 
      .IN 
      ) 
      #IO 0 用作按键 
      while 
      True 
      : 
      if key 
      .value 
      ( 
      ) 
      == 
      0 
      : 
      while key 
      .value 
      ( 
      ) 
      == 
      0 
      : 
      pass ble 
      .gatts_notify 
      ( 
      0 
      , h_repin 
      , 
      b'\xf5\xf5\x00' 
      ) ble 
      .gatts_notify 
      ( 
      0 
      , h_repin 
      , 
      b'\x00\x00\x00' 
      ) 
      
   

上述代码中的BUG

一般的蓝牙设备在配对成功后,下次可以自动连接,上述代码运行后,需要在电脑或手机上删除该设备,再次连接才能生效,只有首次连接可以使用。断开连接后需要删除设备重新配对。

上述文档中的数据格式和取值范围和代码中的ReportMap一一对应,修改ReportMap后,数据格式和取值返回也要做对应的变化。

一般正常的蓝牙HID设备也要包含DIS(Device Information Service)设备信息服务,和BAS(Battery Service)电池电量服务,读者可自行添加。

上一章节:【低功耗蓝牙】④ 蓝牙MIDI协议

作者:我是鹏老师

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/220675.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午7:54
下一篇 2026年3月17日 下午7:54


相关推荐

  • 上位机软件开发入门

    上位机软件开发入门上位机是指:人可以直接发出操控命令的计算机,一般是PC,屏幕上显示各种信号变化(液压,水位,温度等)。下位机是直接控制设备获取设备状况的的计算机,一般是PLC/单片机之类的。上位机发出的命令首先给下位机,下位机再根据此命令解释成相应时序信号直接控制相应设备。下位机不时读取设备状态数据(一般模拟量),转化成数字信号反馈给上位机。上下位机都需要编程,都有专门的开发系统。

    2022年5月6日
    123
  • nema0183 java解析_NEMA 0183 语句解析

    nema0183 java解析_NEMA 0183 语句解析一 NMEA0183 标准语句 GPS 常用语句 1 GlobalPositi GGA GPS 定位信息 GPGGA lt 1 gt lt 2 gt lt 3 gt lt 4 gt lt 5 gt lt 6 gt lt 7 gt lt 8 gt lt 9 gt M lt 10 gt M lt 11 gt lt

    2026年3月16日
    2
  • 基于51单片机的八位流水灯(三种形式)

    基于51单片机的八位流水灯(三种形式)写一下寒假做的51小项目。基于AT89C51的流水灯:流水灯共八个,可以实现交替闪烁,一起闪烁,左右流水灯等效果。模式一:按动key1,实现1,3,5,7和2,4,6,8交替闪烁;模式二:按动key2,实现D1→D8流水灯效果;模式三:按动key3,实现全部闪烁效果,时间间隔为0.5秒;模式四:按动key4,实现D8→D1流水灯效果;模式1:使用P1的取反和delay延时实现模式2…

    2022年6月10日
    37
  • 嵌入式工程师的经典面试题目及答案

    嵌入式工程师的经典面试题目及答案上个星期 去深圳一家搞 ARM 开发的公司面试 HR 叫我做了一份卷子 里面都是 C 编程 心中暗喜 因为这些题基本上都在程序员面试宝典里见过 后来回到学校 在网上搜索 原来这些题都是嵌入式工程师的经典面试题目 很多网站上都可以找得到 现把他贴出来 附上网上的答案 跟大家分享 因为这些题实在太经典了 预处理器 Preprocessor 1 用预处理指令 define 声明一个常数 用以表明 1 年中有多少秒

    2025年12月5日
    6
  • gzip解压_银河麒麟gzip解压

    gzip解压_银河麒麟gzip解压1、首先说为什么采用zlib解压,因为zlib可以解压内存数据。2、下载zlib库后,自己在projcts目录里面根据需要编译lib库3、静态链接只需要zlib.h;zconf.h;zlib.lib三个文件即可(动态的不介绍了)4、解压函数:[html]viewplaincopyprint?/* HTTP gzip decomp

    2025年9月30日
    7
  • 有关公司的各个部门英文缩写简称

    有关公司的各个部门英文缩写简称Inc 表示了公司的性质 CompanyLimit 通常缩写为 Co ltd 或是精简为 Ltd 但是这只是指从公司的性质上说 该公司是一个有限公司不是什么其他的公司 公司名称后面与 Co ltd 之间不应再出现 company 因为 Co 已经包含了公司的意思 再说回来 Inc 的原形是 Incorporatio 意思是指 组成公司 注册 合并 如果加在公司名称后面 多是它的分词形式

    2026年3月19日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号