这个基于STM32单片机的共享充电宝系统设计,是我最近完成的一个嵌入式综合项目。它巧妙地将蓝牙控制、GPS定位、移动支付和物联网技术融合在一起,实现了共享设备的智能化管理。作为一名有多年嵌入式开发经验的工程师,我想分享一下这个项目的完整实现过程和其中的技术细节。
系统采用STM32F103C8T6作为主控芯片,通过蓝牙模块与手机APP通信,配合GPS模块实现设备定位功能。最核心的创新点是加入了二维码验证和计费系统,使得共享充电宝的管理更加安全和便捷。在实际测试中,这套系统运行稳定,定位精度可以达到5米以内,完全满足商业运营的需求。
主控芯片选用STM32F103C8T6,这是一款性价比极高的Cortex-M3内核单片机。选择它的原因主要有三点:首先,72MHz的主频足够处理蓝牙通信和GPS数据;其次,内置的丰富外设接口(USART、I2C、GPIO等)可以方便地连接各种模块;最后,它的低功耗特性非常适合移动设备应用。
电源部分采用18650锂电池供电,配合TP4056充电管理芯片。实测表明,2000mAh的电池可以让系统连续工作约48小时。为了确保系统稳定性,我在电源输入端增加了LC滤波电路,有效抑制了电压波动对GPS模块的干扰。
蓝牙模块选用HC-05,通过USART1与单片机通信。这里有个关键点:需要将模块设置为从机模式,波特率设置为9600bps。GPS模块采用UBLOX NEO-6M,连接USART2,波特率设为38400bps。继电器控制使用常见的5V单路继电器模块,通过PC13引脚控制。
注意:GPS模块的天线位置对定位精度影响很大。建议将天线朝上放置,远离金属部件和电源线路。
硬件连接清单:
系统软件采用前后台架构,主循环负责状态检测和任务调度,中断处理时间敏感的操作。上电后,系统依次初始化各外设模块,然后进入主循环。主循环中主要处理以下任务:
c复制int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init(); // 蓝牙
MX_USART2_UART_Init(); // GPS
MX_TIM2_Init(); // 计时器
while (1) {
Bluetooth_Process();
GPS_Process();
Relay_Check();
Timer_Calculate();
System_Report();
}
}
蓝牙通信采用自定义的简单协议,格式为:$[命令][参数]#。例如:
在代码实现上,使用串口接收中断来收集数据,通过状态机解析协议:
c复制void USART1_IRQHandler(void) {
uint8_t ch = USART1->DR;
switch(parse_state) {
case WAIT_START:
if(ch == '$') parse_state = IN_COMMAND;
break;
case IN_COMMAND:
if(ch == '#') {
parse_state = WAIT_START;
Process_Command();
} else {
cmd_buf[cmd_idx++] = ch;
}
break;
}
}
NEO-6M模块输出标准的NMEA协议数据,主要解析GPRMC语句获取经纬度信息。解析流程如下:
c复制void Parse_GPRMC(char *gps_data) {
char *token = strtok(gps_data, ",");
int field = 0;
while(token != NULL) {
switch(field) {
case 1: // UTC时间
strncpy(gps.time, token, 10);
break;
case 2: // 状态
gps.valid = (token[0] == 'A');
break;
case 3: // 纬度
Parse_Latitude(token);
break;
case 5: // 经度
Parse_Longitude(token);
break;
}
token = strtok(NULL, ",");
field++;
}
}
APP端使用高德地图SDK实现定位显示。关键步骤包括:
Android端核心代码示例:
java复制// 初始化地图
aMap = mapView.getMap();
aMap.setMapType(AMap.MAP_TYPE_NORMAL);
// 设置定位监听
aMap.setOnMyLocationChangeListener(location -> {
LatLng latLng = new LatLng(location.getLatitude(),
location.getLongitude());
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));
});
// 蓝牙数据接收回调
bluetoothReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String data = intent.getStringExtra("gps_data");
updateMapMarker(data);
}
};
系统采用离线二维码验证方案,每个设备有唯一的ID和密钥。二维码内容格式为:deviceID:timestamp:signature。验证流程:
签名算法采用HMAC-SHA256,示例代码:
c复制void Generate_QRCode(char *device_id, char *output) {
time_t now = time(NULL);
char timestamp[20];
sprintf(timestamp, "%ld", now);
unsigned char hmac[32];
HMAC_CTX ctx;
HMAC_Init(&ctx, secret_key, strlen(secret_key), EVP_sha256());
HMAC_Update(&ctx, (unsigned char*)device_id, strlen(device_id));
HMAC_Update(&ctx, (unsigned char*)timestamp, strlen(timestamp));
HMAC_Final(&ctx, hmac, NULL);
char signature[65];
for(int i=0; i<32; i++) {
sprintf(signature+i*2, "%02x", hmac[i]);
}
sprintf(output, "%s:%s:%s", device_id, timestamp, signature);
}
计费逻辑遵循以下规则:
计时器使用STM32的TIM2,配置为1ms中断,在中断服务程序中累加计时:
c复制void TIM2_IRQHandler(void) {
if(TIM2->SR & TIM_SR_UIF) {
TIM2->SR = ~TIM_SR_UIF;
if(relay_state == ON) {
total_ms += 1;
if(total_ms % 1000 == 0) {
current_fee += 0.1f;
if(total_ms >= 60000) {
current_fee = 6.0f;
}
}
}
}
}
蓝牙连接不稳定
GPS定位慢
继电器误动作
通过实测,系统各部分功耗如下:
优化措施:
经过优化后,系统平均工作电流降至15mA左右,显著延长了电池续航时间。
在实际部署中,可以考虑以下改进:
增加GPRS通信模块
多设备组网功能
太阳能充电系统
这个项目最让我满意的部分是它的完整性和实用性。从硬件设计到APP开发,每个环节都经过精心调试。特别是在GPS定位精度优化上,通过多次实测和天线位置调整,最终将定位误差控制在5米以内,这对于共享设备管理来说已经足够精确。