FRDM-MCXN947開發板之i2c應用

来源:https://www.cnblogs.com/hywing/p/18237977
-Advertisement-
Play Games

介紹 MCXN947 NXP FRDM-MCXN947開發板是一款基於MCXN947 MCU的低成本評估板,MCU集成了雙核Arm Cortex-M33微控制器和一個神經處理單元(NPU)。開發板由一個MCXN947控制器和一個64 Mbit外部串列快閃記憶體組成。該板還具有P3T1755DP I3C溫度 ...


介紹

MCXN947

NXP FRDM-MCXN947開發板是一款基於MCXN947 MCU的低成本評估板,MCU集成了雙核Arm Cortex-M33微控制器和一個神經處理單元(NPU)。開發板由一個MCXN947控制器和一個64 Mbit外部串列快閃記憶體組成。該板還具有P3T1755DP I3C溫度感測器,TJA1057GTK/3Z CAN PHY,乙太網PHY, SDHC電路(卡槽為DNP), RGB LED,觸摸板,高速USB,按鈕,和MCU-Link調試介面。該板相容Arduino屏蔽模塊,Pmod板,mikroBUS。該板還支持攝像頭模塊和NXP低成本LCD模塊PAR-LCD-S035

image

開箱視頻

我通過參過RT-Thread社區的活動,拿到了京東的包裹,板子的開箱視頻:FRDM-MCXN947開發板開箱_嗶哩嗶哩_bilibili

開發環境

基本的開發資料有以下幾個,軟體包或者資料都可以在NXP官網、Keil的官網找到,插一句話,最近Keil免費了

  1. MDK531
  2. NXP.MCXN947_DFP.17.0.0
  3. rt_vsnprintf_full-latest.zip開發包
  4. 官方的文檔:UM12018.pdf
  5. RT-Thread GitHub倉庫最新代碼

開發環境搭建請參考視頻:FRDM-MCXN947開發板開發環境上手_嗶哩嗶哩_bilibili

實驗目的

最近南方地區都在下暴雨,氣候悶熱潮濕,人們出門都在時刻關註天氣的變化情況;剛好這個時候RT-Thread社區給我送來一款包裝精緻的NXP開發板,讓我手頭上的BME280溫濕度氣壓感測器有了用武之地;BME280採用i2c介面和主機通信,能實時監控室內、室外的溫度、濕度、大氣壓情況,基於它我們能做很多工業、物聯網、醫療、汽車方面的應用

實驗準備

我們需要準備以下材料

  • NXP FRDM-MCXN947開發板
  • 溫濕度氣壓模塊BME280 (i2c介面)
  • SSD1306 OLED模塊(i2c介面)
  • 公母頭杜邦線若幹

模塊電路

板載資源

本次實驗是通過軟體i2c + 硬體i2c方式來進行通信,軟體i2c採用引腳P0_4 (SCL)和P0_5 (SDA) ,硬體i2c採用引腳P0_25 (SCL)和P0_24 (SDA),前者位於J9內側的第8和第9引腳,後者位於J2外側的第7和第5引腳,引腳圖參考如下,註意不要接錯

image

實物連接

軟體i2c口接OLED SSD1306模塊,硬體i2c口接BME280模塊,電源VCC和GND在J8和J6上面都有,千萬別接錯了!

image

程式設計

模塊配置

克隆rt-thread官方倉庫的代碼,MCXN947板子的最小常式在bsp\nxp\mcx\mcxn\frdm-mcxn947目錄下

git clone https://github.com/RT-Thread/rt-thread.git

用RT-Thread Studio導入frdm-mcxn947工程,然後打開env工具

image

在env終端輸入命令menuconfig,配置rt-thread工程

image

RT-Thread Components下找到Device DriversSelect進去,軟體i2c引腳配置如下

image

Hardware Drivers Config下找到On-chip Peripheral DriversSelect進去,硬體i2c引腳配置如下

image

找到RT-Thread online packages -> peripheral libraries and drivers -> ssd1306Select進去,配置SSD1306模塊,記得改掉I2c bus name和開啟ssd1306的sample選項,這裡名稱為i2c2,和上面配置的軟體i2c名稱一致

image

配置完後通過Exit退出,先更新軟體包,再導出為mdk5工程,然後用Keil5打開

pkgs --update
scons --target=mdk5

編譯工程

需要註釋一些代碼確保編譯通過

ssd1306_tests.h

image

ssd1306.h

image

編碼集成

SSD1306

調用初始化介面並設置背景為黑色

ssd1306_Init();
ssd1306_Fill(Black);

繪圖介面示範,先往buffer裡邊填字元串數據,然後設置坐標,再繪製字元

rt_memset(buffer, SIZE, 0);
rt_snprintf(buffer, SIZE, "Temp : %d'C\r\n",(int)temp_act);
ssd1306_SetCursor(2, 26);
ssd1306_WriteString(buffer, Font_6x8, White);

BME280

readCalibrationDatacalibration_Tcalibration_Pcalibration_H用於讀取和校準BME280的數據

static unsigned long int hum_raw,temp_raw,pres_raw;
static rt_uint8_t data[8];
static signed long int t_fine;
static uint16_t dig_T1;
static int16_t dig_T2;
static int16_t dig_T3;
static uint16_t dig_P1;
static int16_t dig_P2;
static int16_t dig_P3;
static int16_t dig_P4;
static int16_t dig_P5;
static int16_t dig_P6;
static int16_t dig_P7;
static int16_t dig_P8;
static int16_t dig_P9;
static int8_t  dig_H1;
static int16_t dig_H2;
static int8_t  dig_H3;
static int16_t dig_H4;
static int16_t dig_H5;
static int8_t  dig_H6;
static signed long int temp_cal;
static unsigned long int press_cal,hum_cal;
static double temp_act;
static double press_act;
static double hum_act;

static void readCalibrationData()
{
    uint8_t data[32];
    read_bme280_reg(0x88, data, 24);
    read_bme280_reg(0xa1, data + 24, 1);
    read_bme280_reg(0xe1, data + 25, 7);

    dig_T1 = (data[1] << 8) | data[0];
    dig_T2 = (data[3] << 8) | data[2];
    dig_T3 = (data[5] << 8) | data[4];
    dig_P1 = (data[7] << 8) | data[6];
    dig_P2 = (data[9] << 8) | data[8];
    dig_P3 = (data[11]<< 8) | data[10];
    dig_P4 = (data[13]<< 8) | data[12];
    dig_P5 = (data[15]<< 8) | data[14];
    dig_P6 = (data[17]<< 8) | data[16];
    dig_P7 = (data[19]<< 8) | data[18];
    dig_P8 = (data[21]<< 8) | data[20];
    dig_P9 = (data[23]<< 8) | data[22];
    dig_H1 = data[24];
    dig_H2 = (data[26]<< 8) | data[25];
    dig_H3 = data[27];
    dig_H4 = (data[28]<< 4) | (0x0F & data[29]);
    dig_H5 = (data[30] << 4) | ((data[29] >> 4) & 0x0F);
    dig_H6 = data[31];
}

static signed long int calibration_T(signed long int adc_T)
{

    signed long int var1, var2, T;
    var1 = ((((adc_T >> 3) - ((signed long int)dig_T1<<1))) * ((signed long int)dig_T2)) >> 11;
    var2 = (((((adc_T >> 4) - ((signed long int)dig_T1)) * ((adc_T>>4) - ((signed long int)dig_T1))) >> 12) * ((signed long int)dig_T3)) >> 14;

    t_fine = var1 + var2;
    T = (t_fine * 5 + 128) >> 8;
    return T;
}

static unsigned long int calibration_P(signed long int adc_P)
{
    signed long int var1, var2;
    unsigned long int P;
    var1 = (((signed long int)t_fine)>>1) - (signed long int)64000;
    var2 = (((var1>>2) * (var1>>2)) >> 11) * ((signed long int)dig_P6);
    var2 = var2 + ((var1*((signed long int)dig_P5))<<1);
    var2 = (var2>>2)+(((signed long int)dig_P4)<<16);
    var1 = (((dig_P3 * (((var1>>2)*(var1>>2)) >> 13)) >>3) + ((((signed long int)dig_P2) * var1)>>1))>>18;
    var1 = ((((32768+var1))*((signed long int)dig_P1))>>15);
    if (var1 == 0)
    {
        return 0;
    }
    P = (((unsigned long int)(((signed long int)1048576)-adc_P)-(var2>>12)))*3125;
    if(P<0x80000000)
    {
       P = (P << 1) / ((unsigned long int) var1);
    }
    else
    {
        P = (P / (unsigned long int)var1) * 2;
    }
    var1 = (((signed long int)dig_P9) * ((signed long int)(((P>>3) * (P>>3))>>13)))>>12;
    var2 = (((signed long int)(P>>2)) * ((signed long int)dig_P8))>>13;
    P = (unsigned long int)((signed long int)P + ((var1 + var2 + dig_P7) >> 4));
    return P;
}

static unsigned long int calibration_H(signed long int adc_H)
{
    signed long int v_x1;

    v_x1 = (t_fine - ((signed long int)76800));
    v_x1 = (((((adc_H << 14) -(((signed long int)dig_H4) << 20) - (((signed long int)dig_H5) * v_x1)) +
              ((signed long int)16384)) >> 15) * (((((((v_x1 * ((signed long int)dig_H6)) >> 10) *
              (((v_x1 * ((signed long int)dig_H3)) >> 11) + ((signed long int) 32768))) >> 10) + (( signed long int)2097152)) *
              ((signed long int) dig_H2) + 8192) >> 14));
   v_x1 = (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * ((signed long int)dig_H1)) >> 4));
   v_x1 = (v_x1 < 0 ? 0 : v_x1);
   v_x1 = (v_x1 > 419430400 ? 419430400 : v_x1);
   return (unsigned long int)(v_x1 >> 12);
}

i2c讀寫介面封裝

static int read_bme280_reg(rt_uint8_t reg_addr, rt_uint8_t *data, rt_uint8_t len)
{
    struct rt_i2c_msg msgs[2];
    msgs[0].addr = BME280_ADDR;
    msgs[0].flags = RT_I2C_WR;
    msgs[0].buf = &reg_addr;
    msgs[0].len = 1;

    msgs[1].addr = BME280_ADDR;
    msgs[1].flags = RT_I2C_RD;
    msgs[1].buf = data;
    msgs[1].len = len;

    if (rt_i2c_transfer(i2c_bus, msgs, 2) == 2)
    {
        return RT_EOK;
    }
    else
        return -RT_ERROR;
}

static int8_t write_bme280_reg(uint8_t reg, uint8_t *data, uint16_t len)
{
    rt_uint8_t tmp = reg;
    struct rt_i2c_msg msgs[2];

    msgs[0].addr  = BME280_ADDR;                        /* Slave address */
    msgs[0].flags = RT_I2C_WR;                          /* Write flag */
    msgs[0].buf   = &tmp;                               /* Slave register address */
    msgs[0].len   = 1;                                  /* Number of bytes sent */

    msgs[1].addr  = BME280_ADDR;                        /* Slave address */
    msgs[1].flags = RT_I2C_WR | RT_I2C_NO_START;        /* Read flag */
    msgs[1].buf   = data;                               /* Read data pointer */
    msgs[1].len   = len;                                /* Number of bytes read */

    if (rt_i2c_transfer(i2c_bus, msgs, 2) != 2)
    {
        return -RT_ERROR;
    }

    return RT_EOK;
}

init_bme280用於初始化i2c設備

static int init_bme280(void)
{
    i2c_bus = (struct rt_i2c_bus_device *) rt_device_find(BME280_I2C_BUS_NAME);
    if (i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", BME280_I2C_BUS_NAME);
        return RT_ERROR;
    }

    rt_uint8_t data;
    int size = read_bme280_reg(0xD0, &data, 1);
    rt_kprintf("bme280 device id : %x\n", data);

    uint8_t osrs_t = 1;             //Temperature oversampling x 1
    uint8_t osrs_p = 1;             //Pressure oversampling x 1
    uint8_t osrs_h = 1;             //Humidity oversampling x 1
    uint8_t mode = 3;               //Normal mode
    uint8_t t_sb = 5;               //Tstandby 1000ms
    uint8_t filter = 0;             //Filter off
    uint8_t spi3w_en = 0;           //3-wire SPI Disable

    uint8_t ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode;
    uint8_t config_reg    = (t_sb << 5) | (filter << 2) | spi3w_en;
    uint8_t ctrl_hum_reg  = osrs_h;

    write_bme280_reg(0xF2, &ctrl_hum_reg, 1);
    write_bme280_reg(0xF4, &ctrl_meas_reg, 1);
    write_bme280_reg(0xF5, &config_reg, 1);

    readCalibrationData();

    return RT_EOK;
}

將BME280的設置當作一條命令來執行

void run_bme280()
{
	bme280_thread = rt_thread_create("bme280", bme280_entry, RT_NULL, 1024, 16, 20);
    if(bme280_thread != RT_NULL)
    {
        rt_thread_startup(bme280_thread);
    }
}

MSH_CMD_EXPORT(run_bme280, run bme280);

整合代碼

以下代碼經過測試,可以實現本次實驗的所有功能

#include <rtthread.h>
#include <rtdevice.h>
#include "ssd1306.h"

#define LED_PIN                 ((0*32)+10)
#define BME280_I2C_BUS_NAME     "i2c1"
#define BME280_ADDR             0x76
#define SIZE 					50

static struct rt_i2c_bus_device *i2c_bus;
static rt_thread_t bme280_thread = RT_NULL;
static unsigned long int hum_raw,temp_raw,pres_raw;
static rt_uint8_t data[8];

static signed long int t_fine;
static uint16_t dig_T1;
static int16_t dig_T2;
static int16_t dig_T3;
static uint16_t dig_P1;
static int16_t dig_P2;
static int16_t dig_P3;
static int16_t dig_P4;
static int16_t dig_P5;
static int16_t dig_P6;
static int16_t dig_P7;
static int16_t dig_P8;
static int16_t dig_P9;
static int8_t  dig_H1;
static int16_t dig_H2;
static int8_t  dig_H3;
static int16_t dig_H4;
static int16_t dig_H5;
static int8_t  dig_H6;
static signed long int temp_cal;
static unsigned long int press_cal,hum_cal;
static double temp_act;
static double press_act;
static double hum_act;
static char buffer[SIZE];

static signed long int calibration_T(signed long int adc_T)
{

    signed long int var1, var2, T;
    var1 = ((((adc_T >> 3) - ((signed long int)dig_T1<<1))) * ((signed long int)dig_T2)) >> 11;
    var2 = (((((adc_T >> 4) - ((signed long int)dig_T1)) * ((adc_T>>4) - ((signed long int)dig_T1))) >> 12) * ((signed long int)dig_T3)) >> 14;

    t_fine = var1 + var2;
    T = (t_fine * 5 + 128) >> 8;
    return T;
}

static unsigned long int calibration_P(signed long int adc_P)
{
    signed long int var1, var2;
    unsigned long int P;
    var1 = (((signed long int)t_fine)>>1) - (signed long int)64000;
    var2 = (((var1>>2) * (var1>>2)) >> 11) * ((signed long int)dig_P6);
    var2 = var2 + ((var1*((signed long int)dig_P5))<<1);
    var2 = (var2>>2)+(((signed long int)dig_P4)<<16);
    var1 = (((dig_P3 * (((var1>>2)*(var1>>2)) >> 13)) >>3) + ((((signed long int)dig_P2) * var1)>>1))>>18;
    var1 = ((((32768+var1))*((signed long int)dig_P1))>>15);
    if (var1 == 0)
    {
        return 0;
    }
    P = (((unsigned long int)(((signed long int)1048576)-adc_P)-(var2>>12)))*3125;
    if(P<0x80000000)
    {
       P = (P << 1) / ((unsigned long int) var1);
    }
    else
    {
        P = (P / (unsigned long int)var1) * 2;
    }
    var1 = (((signed long int)dig_P9) * ((signed long int)(((P>>3) * (P>>3))>>13)))>>12;
    var2 = (((signed long int)(P>>2)) * ((signed long int)dig_P8))>>13;
    P = (unsigned long int)((signed long int)P + ((var1 + var2 + dig_P7) >> 4));
    return P;
}

static unsigned long int calibration_H(signed long int adc_H)
{
    signed long int v_x1;

    v_x1 = (t_fine - ((signed long int)76800));
    v_x1 = (((((adc_H << 14) -(((signed long int)dig_H4) << 20) - (((signed long int)dig_H5) * v_x1)) +
              ((signed long int)16384)) >> 15) * (((((((v_x1 * ((signed long int)dig_H6)) >> 10) *
              (((v_x1 * ((signed long int)dig_H3)) >> 11) + ((signed long int) 32768))) >> 10) + (( signed long int)2097152)) *
              ((signed long int) dig_H2) + 8192) >> 14));
   v_x1 = (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * ((signed long int)dig_H1)) >> 4));
   v_x1 = (v_x1 < 0 ? 0 : v_x1);
   v_x1 = (v_x1 > 419430400 ? 419430400 : v_x1);
   return (unsigned long int)(v_x1 >> 12);
}

static int read_bme280_reg(rt_uint8_t reg_addr, rt_uint8_t *data, rt_uint8_t len)
{
    struct rt_i2c_msg msgs[2];
    msgs[0].addr = BME280_ADDR;
    msgs[0].flags = RT_I2C_WR;
    msgs[0].buf = &reg_addr;
    msgs[0].len = 1;

    msgs[1].addr = BME280_ADDR;
    msgs[1].flags = RT_I2C_RD;
    msgs[1].buf = data;
    msgs[1].len = len;

    if (rt_i2c_transfer(i2c_bus, msgs, 2) == 2)
    {
        return RT_EOK;
    }
    else
        return -RT_ERROR;
}

static int8_t write_bme280_reg(uint8_t reg, uint8_t *data, uint16_t len)
{
    rt_uint8_t tmp = reg;
    struct rt_i2c_msg msgs[2];

    msgs[0].addr  = BME280_ADDR;                        /* Slave address */
    msgs[0].flags = RT_I2C_WR;                          /* Write flag */
    msgs[0].buf   = &tmp;                               /* Slave register address */
    msgs[0].len   = 1;                                  /* Number of bytes sent */

    msgs[1].addr  = BME280_ADDR;                               /* Slave address */
    msgs[1].flags = RT_I2C_WR | RT_I2C_NO_START;        /* Read flag */
    msgs[1].buf   = data;                               /* Read data pointer */
    msgs[1].len   = len;                                /* Number of bytes read */

    if (rt_i2c_transfer(i2c_bus, msgs, 2) != 2)
    {
        return -RT_ERROR;
    }

    return RT_EOK;
}

static void readCalibrationData()
{
    uint8_t data[32];
    read_bme280_reg(0x88, data, 24);
    read_bme280_reg(0xa1, data + 24, 1);
    read_bme280_reg(0xe1, data + 25, 7);

    dig_T1 = (data[1] << 8) | data[0];
    dig_T2 = (data[3] << 8) | data[2];
    dig_T3 = (data[5] << 8) | data[4];
    dig_P1 = (data[7] << 8) | data[6];
    dig_P2 = (data[9] << 8) | data[8];
    dig_P3 = (data[11]<< 8) | data[10];
    dig_P4 = (data[13]<< 8) | data[12];
    dig_P5 = (data[15]<< 8) | data[14];
    dig_P6 = (data[17]<< 8) | data[16];
    dig_P7 = (data[19]<< 8) | data[18];
    dig_P8 = (data[21]<< 8) | data[20];
    dig_P9 = (data[23]<< 8) | data[22];
    dig_H1 = data[24];
    dig_H2 = (data[26]<< 8) | data[25];
    dig_H3 = data[27];
    dig_H4 = (data[28]<< 4) | (0x0F & data[29]);
    dig_H5 = (data[30] << 4) | ((data[29] >> 4) & 0x0F);
    dig_H6 = data[31];
}

static int init_bme280(void)
{
    rt_uint8_t data;
    int size = read_bme280_reg(0xD0, &data, 1);
    rt_kprintf("bme280 device id : %x\n", data);

    uint8_t osrs_t = 1;             //Temperature oversampling x 1
    uint8_t osrs_p = 1;             //Pressure oversampling x 1
    uint8_t osrs_h = 1;             //Humidity oversampling x 1
    uint8_t mode = 3;               //Normal mode
    uint8_t t_sb = 5;               //Tstandby 1000ms
    uint8_t filter = 0;             //Filter off
    uint8_t spi3w_en = 0;           //3-wire SPI Disable

    uint8_t ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode;
    uint8_t config_reg    = (t_sb << 5) | (filter << 2) | spi3w_en;
    uint8_t ctrl_hum_reg  = osrs_h;

    write_bme280_reg(0xF2, &ctrl_hum_reg, 1);
    write_bme280_reg(0xF4, &ctrl_meas_reg, 1);
    write_bme280_reg(0xF5, &config_reg, 1);

    readCalibrationData();

    return RT_EOK;
}

static void bme280_entry(void* paremeter)
{
    init_bme280();

    while(1)
    {
        read_bme280_reg(0xf7, data, 8);
        pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4);
        temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4);
        hum_raw  = (data[6] << 8) | data[7];

        temp_cal = calibration_T(temp_raw);
        press_cal = calibration_P(pres_raw);
        hum_cal = calibration_H(hum_raw);
        temp_act = (double)temp_cal / 100.0;
        press_act = (double)press_cal;
        hum_act = (double)hum_cal / 1024.0;
		
		rt_memset(buffer, SIZE, 0);
		rt_snprintf(buffer, SIZE, "Temp : %d'C\r\n",(int)temp_act);
		ssd1306_SetCursor(2, 26);
		ssd1306_WriteString(buffer, Font_6x8, White);
		
		
		rt_memset(buffer, SIZE, 0);
		rt_snprintf(buffer, SIZE, "Humi : %d %\r\n",(int)hum_act);
		ssd1306_SetCursor(2, 26 + 10);
		ssd1306_WriteString(buffer, Font_6x8, White);
		
		
		rt_memset(buffer, SIZE, 0);
		rt_snprintf(buffer, SIZE, "Press : %d Pa\r\n",(int)press_act);
		ssd1306_SetCursor(2, 26 + 10 + 10);
		ssd1306_WriteString(buffer, Font_6x8, White);
		
        rt_thread_mdelay(500);
		ssd1306_UpdateScreen();
    }
}

void run_bme280()
{
	bme280_thread = rt_thread_create("bme280", bme280_entry, RT_NULL, 1024, 16, 20);
    if(bme280_thread != RT_NULL)
    {
        rt_thread_startup(bme280_thread);
    }
}

MSH_CMD_EXPORT(run_bme280, run bme280);

int main(void)
{
	i2c_bus = (struct rt_i2c_bus_device *) rt_device_find(BME280_I2C_BUS_NAME);
    if (i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", BME280_I2C_BUS_NAME);
        return RT_ERROR;
    }
		
	ssd1306_Init();
	ssd1306_Fill(Black);
		
    rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
    for (;;)
    {
        rt_pin_write(LED_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED_PIN, PIN_LOW);
        rt_thread_mdelay(500);
    }
}

實驗效果

用串口工具打開開發板對應的串口,命令行輸入run_bme280

image

效果如下,OLED實時展示當前環境的溫度、濕度、大氣壓

image

總結

  • 技術離不開應用、離不開生活,學習技術是為了更好的服務於社會
  • NXP的硬體i2c比較複雜,官方的demo比較多、配置也複雜,理解起來確實有一點難度,我在用i2c-tool工具的時候遇到了一些問題,目前還在分析、定位中

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一:背景 1. 講故事 這些天有點意思,遇到的幾個程式故障都是和Windows操作系統或者第三方組件有關係,真的有點無語,今天就帶給大家一例 IIS 相關的與大家分享,這是一家國企的.NET程式,出現了崩潰急需分析。 二:WinDbg 分析 1. 為什麼會崩潰 崩潰原因相對還是好找的,雙擊dump文 ...
  • 目錄知識補給站對文件描述符集合操作的四個巨集操作伺服器IO多路復用中的select和poll的區別 知識補給站 對文件描述符集合操作的四個巨集操作 對文件描述符集合操作的四個巨集操作在select函數中起著關鍵的作用,它們用於初始化、添加、刪除和檢查文件描述符集合中的元素。這四個巨集為: FD_ZERO、F ...
  • 前言 筆者做過一段時間的車載LiDAR開發,對LidarView開源項目進行過深度定製,摸索了一套LidarView軟體的開發和調試方法 1 軟體安裝 1.1 安裝準備 以Windows10系統平臺為例,依次下載以下工具軟體,軟體(VS、Qt、cdb)的版本很重要!以下版本經過驗證是沒有問題的 序號 ...
  • 前言 最近調試NXP FRDM-MCXN947開發板,發現它的硬體i2c介面讀取的感測器數據老是不對,排查了硬體電路也發現不了啥問題;於是乎想到用邏輯分析儀試一下,果然很快定位到問題所在;還是那句話,用對的工具做對的事情,別浪費時間!這篇文章主要關於邏輯分析儀的使用教程 介紹 nanoDLA 是Mu ...
  • 第一步:下載鏡像文件 百度網盤下載https://pan.baidu.com/s/1efRQGFTbq6Kgw9axLOmWzg?pwd=emxf 第二步:打開Vmware 第三步:進行各項配置 創建新的虛擬機,選擇高級,然後下一步 直接預設下一步 選擇稍後安裝然後下一步 kali屬於Debian系 ...
  • 最近想移植個LVGL玩玩,發現文件實在是太多了,加的手疼都沒搞完,實在不想搞了就去找腳本和工具,基本沒找到一個。。。。。。 主要是自己也懶得去研究寫腳本,偶然搜到了一個博主寫的腳本,原博客地址:https://blog.csdn.net/riyue2044/article/details/13942 ...
  • 初識FreeRTOS 什麼是FreeRTOS RTOS (實時操作系統)並不是指某一特定的操作系統,而是指一類操作系統,例如, µC/OS,FreeRTOS, RTX, RT-Thread 等這些都是 RTOS 類的操作系統。 因此,從 FreeRTOS 的名字中就能看出, FreeROTS 是一款 ...
  • 介紹 RT-Thread Studio是官方出品的一款專門針對RT-Thread嵌入式開發、部署、調試、測試的集成開發環境,它基於Eclipse開源項目開發,極大的提高了嵌入式開發者的開發效率,目前最新版本是2.26 下載 使用瀏覽器打開RT-Thread官網,選擇左上角資源點擊RT-Thread ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...