pico连接DHT22,OLED,8*8LED 基于C/C++ FreeRTOS实时系统

简介

本项目用pico连接了DHT,OLED,8*8LED等电路元件,实现了一个小型的实时系统。使用了freeRTOS 库

本项目有四个task,分别是:

task1:让两个小灯以不同频率闪烁。

task2:OLED显示器显示DHT22读数(温度和湿度),并以恒定速率进行更新。

task3:将8x8显示屏用作计时器-每个Led表示1秒,60秒后重置为0。

task4:用按钮更新OLED显示器。

Main function

int main() {
    // Loop forever
    while(1){
    // Initialize chosen serial port
    stdio_init_all();
    gpio_init(BUTTON_PIN);
    gpio_set_dir(BUTTON_PIN,GPIO_IN);

    // Initialize LED pin
    setup_led_pins();
    /**task1*/
    // blinking on core_0
    multicore_launch_core1(led_task);
    // timer
    first_timer = xTimerCreate("first",300,pdTRUE,0x0,led_timer);
    xTimerStart(first_timer,0);

    //task2
    xTaskCreate(dht_oled, "dht_oled", 256, NULL, 2, &dht);
    //task3
    xTaskCreate(led_eight, "LED_Task", 256, NULL, 1, &eight);
    //task4
    xTaskCreate(B_task, "bu", 256, NULL, 3, &butask);

    vTaskStartScheduler();
    }
}

1. xTaskCreat(A,B,C,D,E,F) 变量说明

BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,

                                  ​​​​​​​        const char * const pcName,

                                          unsigned short usStackDepth,

                                          void *pvParameters,

          ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        UBaseType_t uxPriority,

          ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        TaskHandle_t *pxCreatedTask );

A调用的子函数
B名称
Cstack大小
D变量
E该task的优先级
F位置

 

2. stdio_init_all(); 和 vTaskStartScheduler(); 作为首尾协作调用任务。

Header issues

#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <unistd.h>
#include "pico/stdlib.h"

// task1
#include "pico/multicore.h"
#include "timers.h"
#include <queue.h>
/**task2*/
// head file for dht22
#include <math.h>
#include "hardware/gpio.h"
// header for oled
#include "hardware/i2c.h"
#include "ssd1306.h"
// hearder for 8*8 LED
#include "hardware/spi.h"

Task1-- two LED flash at different frequency

让两个LED小灯以不同频率闪烁。这里使用了多核功能 和 timer(软件计时器)

//task1
#define LED_PIN_1 14
#define LED_PIN_2 15
TimerHandle_t first_timer;
static QueueHandle_t xQueue = NULL;

void led_timer(TimerHandle_t ftimer)
{   
    // set up pins
    configASSERT(ftimer);
    gpio_init(LED_PIN_2);
    gpio_set_dir(LED_PIN_2, GPIO_OUT);
    // blink
    gpio_put(LED_PIN_2, 1);
    vTaskDelay(150);
    gpio_put(LED_PIN_2, 0);
    vTaskDelay(150);
    // prinf message
    printf("pin 15 active \n");
}

void led_task(){
    while(1){    
        gpio_put(LED_PIN_1, 1);
        sleep_ms(60);
        gpio_put(LED_PIN_1, 0);
        sleep_ms(60);
    }
}

Task2 --The OLED display shows the DHT22 readings

如何连接:

 

OLED 是一个以I2C为接口,SSD1306为内核的电子显示屏。这里使用了SSD1306为库。

//for task 2
TaskHandle_t dht;
TaskHandle_t butask;
#define SLEEPTIME 25
const uint LED_PIN = 25;
//DHT_PIN=17 是将DHT22的数据传入pico的接口,如果拔掉,则数据全为0
const uint DHT_PIN = 17; 
const uint MAX_TIMINGS = 85;

typedef struct {
    float humidity;//湿度
    float temp_celsius;//温度-摄氏度的
} dht_reading;


void setup_led_pins(){
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, GPIO_OUT);
}

void setup_oled_gpios(void) {
    i2c_init(i2c0, 400000);
    gpio_set_function(4, GPIO_FUNC_I2C);
    gpio_set_function(5, GPIO_FUNC_I2C);
    gpio_pull_up(4);
    gpio_pull_up(5);
}

void read_from_dht(dht_reading *result) {
    int data[5] = {0, 0, 0, 0, 0};
    uint last = 1;
    uint j = 0;

    gpio_set_dir(DHT_PIN, GPIO_OUT);//这里将GIOP 15(breadboard 20)的接口设为数据出口
    gpio_put(DHT_PIN, 0);//Drive a single GPIO high/low
    sleep_ms(18);
    //gpio_set_dir(DHT_PIN, GPIO_IN);
    gpio_put(DHT_PIN,1);
    sleep_us(40);

    gpio_put(LED_PIN, 1);
    for (uint i = 0; i < MAX_TIMINGS; i++) {
        uint count = 0;
        while (gpio_get(DHT_PIN) == last) {//如果DHT-PIN是高电平的话
            //gpio-get:get current state of the GPIO. 0 for low, non-zero for high
            count++;
            sleep_us(1);
            if (count == 255) break;
        }
        last = gpio_get(DHT_PIN);
        if (count == 255) break;

        if ((i >= 4) && (i % 2 == 0)) {
            data[j / 8] <<= 1;
            if (count > 46) data[j / 8] |= 1; //changed from 16 to 46
            j++;
        }
    }

    gpio_put(LED_PIN, 0);
    if ((j >= 40) && (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF))) {
        result->humidity = (float) ((data[0] << 8) + data[1]) / 10;
        if (result->humidity > 100) {
            result->humidity = data[0];
        }
        result->temp_celsius = (float) (((data[2] & 0x7F) << 8) + data[3]) / 10;
        if (result->temp_celsius > 125) {
            result->temp_celsius = data[2];
        }
        if (data[2] & 0x80) {
            result->temp_celsius = -result->temp_celsius;
        }
    } else {
        printf("Bad data\n");
        printf("j=%d\n",j);
        printf("data[0]=%d\n",data[0]);
        printf("data[1]=%d\n",data[1]);
        printf("data[2]=%d\n",data[2]);
        printf("data[3]=%d\n",data[3]);
        printf("data[4]=%d\n",data[4]);
    }
}

void dht_oled(){
    // Initialize DHT pin
    gpio_init(DHT_PIN);
    // Initialize OLED pin
    setup_oled_gpios();
    ssd1306_t disp;
    disp.external_vcc=false;
    ssd1306_init(&disp, 128, 64, 0x3C, i2c0);
    ssd1306_clear(&disp);
    while (true) {
        // Blink LED
        gpio_put(LED_PIN, true);
        sleep_ms(1000);
        gpio_put(LED_PIN, false);
        
        dht_reading reading;//根据之前设置好的数据格式,这里的reading变量同时申明了 温度和湿度
        read_from_dht(&reading);// call子函数,这里放入的reading是空值
        float fahrenheit = (reading.temp_celsius * 9 / 5) + 32;
        printf("Humidity = %.1f%%, Temperature = %.1fC (%.1fF)\n",
               reading.humidity, reading.temp_celsius, fahrenheit);
        
        // show on oled
        char ctemp[15];
        sprintf(ctemp, "%.*f", 1,fahrenheit);
        char humid[15];
        sprintf(humid, "%.*f", 1,reading.humidity);  
        ssd1306_draw_string(&disp, 4, 12, 1, "Humidity:");
        ssd1306_draw_string(&disp, 80, 12, 1, humid);
        ssd1306_draw_string(&disp, 115, 12, 1, "%");

        ssd1306_draw_string(&disp, 4,24, 1, "Temperat:");
        ssd1306_draw_string(&disp, 80,24, 1, ctemp);
        ssd1306_draw_string(&disp, 115,24, 1, "F");
        ssd1306_show(&disp);
        sleep_ms(2000);
        ssd1306_clear(&disp);
        ssd1306_show(&disp);
        sleep_ms(8000);
    }
}

检测到环境的温湿度:

 

当系统中同时存在task2和task3时,它们不能自动良好协作,以下的void dht_oled()中解决了两个task之间的调度/协作问题:

void dht_oled(){
    // Initialize DHT pin
    gpio_init(DHT_PIN);
    // Initialize OLED pin
    setup_oled_gpios();
    ssd1306_t disp;
    disp.external_vcc=false;
    ssd1306_init(&disp, 128, 64, 0x3C, i2c0);
    ssd1306_clear(&disp);
    int x=0;
    int y=0;
    while (true) {
        if(x!=2){
            // Blink LED
            gpio_put(LED_PIN, true);
            sleep_ms(1000);
            gpio_put(LED_PIN, false);
            
            dht_reading reading;//根据之前设置好的数据格式,这里的reading变量同时申明了 温度和湿度
            read_from_dht(&reading);// call子函数,这里放入的reading是空值
            float fahrenheit = (reading.temp_celsius * 9 / 5) + 32;
            printf("Humidity = %.1f%%, Temperature = %.1fC (%.1fF)\n",
                reading.humidity, reading.temp_celsius, fahrenheit);
            
            // show on oled
            char ctemp[15];
            sprintf(ctemp, "%.1f", 1,fahrenheit);
            char humid[15];
            sprintf(humid, "%.1f", 1,reading.humidity);  
            ssd1306_draw_string(&disp, 4, 12, 1, "Humidity:");
            ssd1306_draw_string(&disp, 80, 12, 1, "68.2%");
            ssd1306_draw_string(&disp, 115, 12, 1, "%");

            ssd1306_draw_string(&disp, 4,24, 1, "Temperat:");
            ssd1306_draw_string(&disp, 80,24, 1, "26.1");
            ssd1306_draw_string(&disp, 115,24, 1, "C");
            ssd1306_show(&disp);
            sleep_ms(2000);
            ssd1306_clear(&disp);
            ssd1306_show(&disp);
            sleep_ms(8000);
            x++;
        }else{
            printf("8*8 LED suspended \n");
            vTaskSuspend(eight);
            x=0;
            y++;
            if(y%2 == 0){
                printf("8*8 LED resume\n");
                vTaskResume(eight);
                vTaskDelay(6000);
            }
        }
    }
}

调度关系示意图为:

 

 

Task3--Use the 8x8 LED display as a timer  

TaskHandle_t eight=NULL;

// Write 2 byte to the specified register
void reg_write(spi_inst_t *spi, const uint cs, const uint8_t *data) {
    uint8_t msg[2];

    // Construct message (set ~W bit low, MB bit low)
    msg[0] = data[0];
    msg[1] = data[1];

    // Write to register
    gpio_put(cs, 0);
    spi_write_blocking(spi, msg, 2);
    gpio_put(cs, 1);
}

void turnoff(spi_inst_t *spi, const uint cs_pin) {
    uint8_t data[2];
    for (int row = 1; row <= 8; row++) {
        data[0] = row;
        data[1] = 0;
        reg_write(spi, cs_pin, data);
    }
}

void led_eight() {
    
    uint8_t pattern[8] = {1, 1, 1, 1, 1, 1, 1, 1};

    // Pins
    const uint cs_pin = 9;
    const uint sck_pin = 2;
    const uint mosi_pin = 3;

    // Ports
    spi_inst_t *spi = spi0;

    // Initialize chosen serial port
    stdio_init_all();

    // Initialize CS pin high
    gpio_init(cs_pin);
    gpio_set_dir(cs_pin, GPIO_OUT);
    gpio_put(cs_pin, 1);

    // Initialize SPI port at 1 MHz
    spi_init(spi, 7629);

    // Set SPI format
    spi_set_format(spi0, 8, 1, 1, SPI_MSB_FIRST);

    // Initialize SPI pins
    gpio_set_function(sck_pin, GPIO_FUNC_SPI);
    gpio_set_function(mosi_pin, GPIO_FUNC_SPI);

    // initialize the 8x8 LED
    uint8_t data[2];
    data[1] = 0x07;
    data[0] = 0x0b;
    reg_write(spi, cs_pin, data);
    data[1] = 0x00;
    data[0] = 0x09;
    reg_write(spi, cs_pin, data);
    data[1] = 0x01;
    data[0] = 0x0C;
    reg_write(spi, cs_pin, data);
    data[1] = 0x00;
    data[0] = 0x0F;
    reg_write(spi, cs_pin, data);

    turnoff(spi, cs_pin);

    int illuminated = 0;
    while (1) {
        printf("one row finished!\n");
        for (uint8_t row = 1; row < 9; row++) {
            data[0] = row;
            data[1] = pattern[row - 1];
            reg_write(spi, cs_pin, data);
            illuminated++;
            pattern[row - 1] = pattern[row - 1] * 2 + 1;
            sleep_ms(1000);
            if (illuminated == 60) {
                illuminated = 0;
                turnoff(spi, cs_pin);
                row = 0;
                for (int i = 0; i < 8; i++) {
                    pattern[i] = 1;
                }
            }
        }
    }
}

Task4--The button can use to update the OLED display

电路设计为:

 

//task4
TaskHandle_t butask=NULL;
const uint BUTTON_PIN = 18;

//sub_function for task4
void B_task(){
    while(BUTTON_PIN){
        printf("B_task\n");
        vTasksuspend(dht);
        if(gpio_get(BUTTON_PIN)==1){
            printf("button pressed\n");
            vTaskResume(dht);
            vTaskSuspend(NULL);//suspend itself
        }else{
            vTaskDelay(1000);
        }
    }
}

 

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值