【Funpack3-1】基于XG24-EK2703A的温度可视化
该项目使用了XG24-EK2703A,实现了基于XG24-EK2703A的温度可视化的设计,它的主要功能为:基于EFR32MG24,板上有1536 kBMFlash、256kB的RAM,。 2.使用了XG24-EK2703A开发套件、C语言,BLE_SDK 实现了无线传感器温度可视化的设计,它的主要功能为:。 利用EFR32内置的温度传感器,通过BLE发送给上位机进行可视化,上位机通过pyqt提供ui界面,用pyqtgraph绘制温度变化曲线。。
标签
嵌入式系统
Funpack活动
显示
x鑫鑫
更新2024-03-05
信阳学院
216

项目介绍

基于EFR32MG24片上系统的温度可视化

  1. 使用EFR32的BLE_SDK实现蓝牙功能
  2. 初始化内置温度传感器,并通过蓝牙发送出去
  3. 使用python的bleak连接下位机EFR32 ,并把数据传递给pyqtgraph

设计思路

Silicon Labs提供的IDE有一个非常强大的且好用的的功能software component,使用它可以很方便完成对板载的led,vcom,温度传感器的驱动文件的添加。使得我们只需关心温度的读取及发送即可。难点就在于上位机通信 ,解析温度数据。

我使用的是bleak(一个异步的BLE库),pyqt5及pyqtgraph图表来制作上位机。

硬件介绍

XG24-EK2703A开发板分成两部分,第一部分是EFM32GG12构成的jlink下载器,支持虚拟串口,在线调试的功能。第二部分是本次任务的芯片EFR32MG24以及两颗用户按键和LED。

软件部分

下位机

  1. 由IDE在sl_system_init完成对蓝牙协议栈的初始化,对芯片的时钟初始化,堆栈分配
  2. 在appinit里完成GPIO初始化,温度传感器初始化
  3. 在sl_system_process_action里完成添加蓝牙任务,启动定时器定时发送温度数据。
  4. temperature_measurement_val_to_buf数据封装

上位机

  1. 安装并导入pyqt,asyncio,bleak,pyqtgraph库
  2. 开启多线程并把bleak蓝牙事务处理单独放在一个线程中,防止主界面卡死
    1. bleak作为异步蓝牙通信库,使用协程来完成蓝牙数据处理
    2. 协程是单线程下,提高数据接收,发送效率的机制
    3. 在处理网络通信,IO事件耗时操作时,不会死等而是去执行其他异步任务
  3. 利用信号-槽机制把接收的数据发送到pyqtgraph里
  4. 数据解码并绘图

软件流程图

蓝牙任务创建的流程图

这里面尤其要指出sl_bt_ht_temperature_measurement_indicate完成把原始温度数据封装到长度为5的buff数组中。

还有sl_bt_gatt_server_send_indication()函数是最底层的向上位机发送经过封装后的温度数据的函数。

因此上位机要想得到的正确的数据必须用indication属性来接收,之后要把buff数组内的数据再还原回封装前的值。

上位机,下位机流程图

主要代码和说明

下位机

1.硬件初始化

SL_WEAK void app_init(void)
{
/////////////////////////////////////////////////////////////////////////////
// Put your additional application init code here! 1秒 //
printf("start");
sl_simple_led_context_t led;
led.port=gpioPortA;
led.pin=4;
led.polarity=SL_SIMPLE_LED_POLARITY_ACTIVE_HIGH;

CMU_ClockEnable(cmuClock_GPIO, true);//时钟使能

GPIO_PinModeSet(led.port,
led.pin,
gpioModePushPull,
!led.polarity);//初始化GPIO的配置的
GPIO_PinOutSet(led.port,led.pin);//输出高电平
//sl_iostream_usart_vcom_config 硬件配置
led.pin=7;
GPIO_PinModeSet(led.port,

led.pin,

gpioModePushPull,

!led.polarity);

GPIO_PortOutClear(led.port,led.pin);//输出低电平

sl_sensor_rht_init();//初始化传感器

}

2.传感器初始化

void sl_sensor_rht_init(void)//传感器初始化
{
Ecode_t er;
// Init TEMPDRV
er = TEMPDRV_Init();
if (er != ECODE_EMDRV_TEMPDRV_OK) {
has_tempdrv = false;
return SL_STATUS_INITIALIZATION;
}
// Enable TEMPDRV
er = TEMPDRV_Enable(true);
if (er != ECODE_EMDRV_TEMPDRV_OK) {
TEMPDRV_DeInit();
has_tempdrv = false;
return SL_STATUS_INITIALIZATION;
}
// Reset to base values
temperature_millicelsius = T_MIN;
has_tempdrv = true;
return SL_STATUS_OK;
}

3.获取温度数据

sl_status_t sl_sensor_rht_get(int32_t *t)
{
sl_status_t sc = SL_STATUS_OK;
// Get temperature from TEMPDRV

int32_t temperature_celsius = (int32_t)TEMPDRV_GetTemp();

temperature_millicelsius = temperature_celsius * 1000;

(*t) = temperature_millicelsius;
return sc;

}

4.蓝牙任务

 void sl_bt_ht_temperature_measurement_indication_changed_cb(uint8_t connection,
sl_bt_gatt_client_config_flag_t client_config)
{printf("sl_bt_ht_temperature_measurement_indication_changed_cb");

app_connection = connection;//获取蓝牙链接句柄
app_timer_start(&app_periodic_timer,
1 * 1000,
app_periodic_timer_cb,
NULL,
true);//开启定时器
}
//定时器回调 1秒中一次
static void app_periodic_timer_cb(app_timer_t *timer, void *data)
{


GPIO_PinOutToggle(led.port,7);
int32_t temperature = 0;
int tmp_c = 0.0;
// float tmp_f = 0.0;

// Measure temperature; units are % and milli-Celsius.
sl_sensor_rht_get( &temperature);
tmp_c = temperature / 1000;
printf("Temperature____123: %d\n", tmp_c);
sl_bt_ht_temperature_measurement_indicate(app_connection, temperature, false);


}




//蓝牙发送函数
sl_status_t sl_bt_ht_temperature_measurement_indicate(uint8_t connection,
int32_t value,
bool fahrenheit)
{
sl_status_t sc;
uint8_t buf[5] = { 0 };
temperature_measurement_val_to_buf(value, fahrenheit, buf);
sc = sl_bt_gatt_server_send_indication(
connection,
gattdb_ccx24,
sizeof(buf),
buf);
return sc;
}






5.数据封装

static void temperature_measurement_val_to_buf(int32_t value,
bool fahrenheit,
uint8_t *buffer)
{
uint32_t tmp_value = ((uint32_t)value & 0x00ffffffu) \
| ((uint32_t)(-3) << 24);
buffer[0] = 0;
//app_log_info(" tmp_value%d\n", tmp_value);

buffer[1] = tmp_value & 0xff;
// app_log_info(" buffer[1]%d\n", buffer[1]);
buffer[2] = (tmp_value >> 8) & 0xff;
// app_log_info(" buffer[2]%d\n", buffer[2]);
buffer[3] = (tmp_value >> 16) & 0xff;
// app_log_info(" buffer[3]%d\n", buffer[3]);
buffer[4] = (tmp_value >> 24) & 0xff;
// app_log_info(" buffer[4]%d\n", buffer[4]);
}

上位机

1.蓝牙扫描

    async def handle_scan(self):
        self.log_edit.appendPlainText("Started scanner")
        self.devices.clear()
        devices = await BleakScanner.discover()
        self.devices.extend(devices)
        self.devices_combobox.clear()
        for i, device in enumerate(self.devices):
            self.devices_combobox.insertItem(i, device.name, device)
        self.log_edit.appendPlainText("Finish scanner")

2.蓝牙链接建立

    async def build_client(self, device):
        if self._client is not None:
            await self._client.stop()
        self._client = QBleakClient(device)
        self._client.messageChanged.connect(self.handle_message_changed)
        await self._client.start()

  await self._client.start()将会开启一个线程 用来处理蓝牙接收任务

3.数据处理

    async def start(self):

        await self.client.connect()
        await self.client.start_notify(UART_TX_CHAR_UUID, self._handle_read)//开启indicate数据接收
 
    def _handle_read(self, _: int, data: bytearray) -> None:
        print("received:", data)//数据转换
        a= (data[4]<<8)|data[3];
        a=(a<<8)|data[2];
        a=(a<<8)|data[1];
        a=a&0xffffff;
        #print("sent:", a)
        self.messageChanged.emit(a/1000)数据发送到主线程

  def handle_message_changed(self, message):
        self.log_edit.appendPlainText(f"msg: "+str(message))
        q.put(message)
        global i
        global length

4.绘图

    def update(self):
        global i
        #dil=[1,0,8,9]
        #print(list_number)
        for a in range(0,length):
            if(q.qsize()<length):
                pass
        #self.curve.setData(list_number)
        self.curve.setData(list(q.queue))//温度曲线数据
        if(q.qsize()==50):
            q.queue.clear()    
        #q.queue.clear()
        i=i+1
        self.curve.setPos(i, 0)



功能展示及说明

如果需要重新连接上位机与开发板,请按板子上的rest键,断开蓝牙。

XG24-EK2703A连接蓝牙后led闪烁

温度数据可视化

本活动的心得体会

1.第一次参加Funpack活动感觉非常有趣,当然也存在一些困难,在群友的集思广益和厂商的丰富资料下,最终得以完成。

2.希望视频资料,中文资料能够再多些,最好有一些零基础的开发资料。

3希望.板子上能够再增加一些屏幕,传感器的外设。


附件下载
v6.py
上位机源码,需要下载相应的库
bt_soc_empty.bin
下位机程序
bt_soc_empty.7z
源码
团队介绍
尚鑫
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号