打印
[STM32F1]

【转】uC/OS室温计

[复制链接]
614|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一代掌门|  楼主 | 2016-12-25 12:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、           实验目的和要求
1.     学习Uc/OS II的应用程序编写;
2.     理解如何直接操作GPIO,体会与Linux的不同;
3.     学习单总线设备的访问方式;
4.     学习7段数码管的实时复用驱动方式。

二、           实验器材
1.     STM32F103核心板一块;
2.     MicroUSB线一根;
3.     面包板一块;
4.     两位7段数码管(共阳)一颗;
5.     360ou 1/8W电阻2颗;
6.     DHT-11温湿度传感器1个;
7.     面包线若干;
8.     编译软件;
9.     Fritzing

三、           实验内容和原理
1.设计输出方案,画连线示意图;
2.在面包板上连线,完成外部电路;
3.编写C/C++程序,测试程序和电路;
a)       测试、实现uC/OS对GPIO的访问;
b)       实现DHT-11数据的读
c)       实现以时分复用方式在四位7段数码管上一次现实0000-9999数字
d)       用两个uC/OS II人物,一个定时读DHT-11数据,一个轮流驱动数码管,一秒一次显示当前温度和湿度。注意处理好两个任务之间的数据共享。

四、           实验过程和数据记录
1.     首先使用Fritzing画出面包板示意图,示意图如下:



2.     然后在面包板上连线,连线图如下:




3.     下面使用C/C++编写程序
a.      测试、实现uC/OS对GPIO的访问;
配置相关GPIO端口,使用A11-12,C14-15作为7端数码管的选择位,使用A0-7作为7端数码管各led的显示。
void GPIO_Configuration(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_DeInit();
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOA, ENABLE);
    //C14-15初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14
                                | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    //A0-7,11-12初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin0-7...11-12;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

b.     实现DHT-11数据的读
uint8_t DHT11_Check()
{
    return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8);
}

void DHT11_Wait(int state)
{
    while (DHT11_Check() != state);
}

void DHT11_Rst(){
    //请求数据协议
    DHT11_Pin_OUT();
    DHT11_Set(0);
    Delay_us(25000);
    DHT11_Set(1);
    Delay_us(30);
    DHT11_Set(0);
    DHT11_Pin_IN();
}
//5次读取中每次读取的数据
uint8_t DHT11_Read_Byte(){
    int i, cnt;
    uint8_t data = 0;
    for (i=0; i<8; i++){
        cnt = 0;
        data <<= 1;
        DHT11_Wait(1);
        while (DHT11_Check() > 0){
            Delay_us(1);
            cnt++;
        }
        data |= cnt > 5;
    }
    return data;
}
//读取一次完整数据到buf中
uint8_t DHT11_Read_Data(uint8_t *buf){
    int i;
    int cpu_sr;
    //DHT11对数据交换时时间要求高,故需要关闭中断以防协议中断。
    OS_ENTER_CRITICAL();
    DHT11_Rst();
    if (DHT11_Check() == 0){
        DHT11_Wait(1);
        DHT11_Wait(0);
        for (i=0; i<5; i++){
            buf = DHT11_Read_Byte();
        }
        DHT11_Pin_OUT();
        OS_EXIT_CRITICAL();
        // 读取的第五个数据为校验数据
        if (buf[0] + buf[1] + buf[2] + buf[3] == buf[4]){
            return 1;
        }else{
            return 0;
        }
    }else{
        OS_EXIT_CRITICAL();
           return 0;
    }
}



沙发
一代掌门|  楼主 | 2016-12-25 12:50 | 只看该作者
c.      实现以时分复用方式在四位7段数码管上一次现实0000-9999数字

由于有共阳极的特性,七段数码管需要使用时分复用的方式进行显示数据。
//选择显示数据位,4位输出数据只有一个置位,其为选择显示的位
void digit_select(int index)
{
    BitAction v[4];
    int i;
    for (i=0; i<4; i++){
        //根据index选择显示位
        if (index == i){
            v = Bit_SET;
        }else{
            v = Bit_RESET;
        }
    }
    GPIO_WriteBit(GPIOA, GPIO_Pin_11, v[0]);
    GPIO_WriteBit(GPIOA, GPIO_Pin_12, v[1]);
    GPIO_WriteBit(GPIOC, GPIO_Pin_14, v[2]);
    GPIO_WriteBit(GPIOC, GPIO_Pin_15, v[3]);
}
//根据输入数字点亮对应led,共8位,包括小数点以及7段数码管
void digit_show(int digit)
{
    int segment, i, base;
    BitAction v[8];
    switch (digit){
        case    0    :    segment = 0xc0; break;
        case    1    :    segment = 0xf9; break;
        case    2    :    segment = 0xa4; break;
        case    3    :    segment = 0xb0; break;
        case    4    :    segment = 0x99; break;
        case    5    :    segment = 0x92; break;
        case    6    :    segment = 0x82; break;
        case    7    :    segment = 0xf8; break;
        case    8    :    segment = 0x80; break;
        case    9    :    segment = 0x90; break;
        default      :    segment = 0x86; break;
    }
    base = 1 << 8;
    // 由于数码管为共阳极,所以此处置位为不显示。
    for (i=0; i<8; i++){
        base >>= 1;
        if ((segment & base )== 0){
            v = Bit_RESET;
        }else{
            v = Bit_SET;
        }
    }
    GPIO_WriteBit(GPIOA, GPIO_Pin_0, v[0]);
    GPIO_WriteBit(GPIOA, GPIO_Pin_1, v[7]);
    GPIO_WriteBit(GPIOA, GPIO_Pin_2, v[6]);
    GPIO_WriteBit(GPIOA, GPIO_Pin_3, v[5]);
    GPIO_WriteBit(GPIOA, GPIO_Pin_4, v[4]);
    GPIO_WriteBit(GPIOA, GPIO_Pin_5, v[3]);
    GPIO_WriteBit(GPIOA, GPIO_Pin_6, v[2]);
    GPIO_WriteBit(GPIOA, GPIO_Pin_7, v[1]);
}
//控制时分复用,每调用一次显示对应的一位,使用静态变量控制选择位
void display(int digit){
    static int index = -1;
    int i;
    int base = 1000;
    index = (index + 1) % 4;
    //index=0-3时分别对应从左到右四位
    for (i=0; i<index; i++){
        base /= 10;
    }
    digit = (digit / base) % 10;
    digit_select(index);
    digit_show(digit);
}


显示0000-9999的功能调用display函数。由于其需要显示一段时间才能显示完整的四位数字,所以需要循环一段时间。
void ShowData(void* pdata)
{
        int value, i;
        for (value = 0; value < 10000 ;value += 1111){
            for (i = 0; i < 200; i++){
                display(value);
                Delay_ms(5);
            }
            if (value == 9999)
                value = 0;
        }
}

下图是显示效果




d.     用两个uC/OS II人物,一个定时读DHT-11数据,一个轮流驱动数码管,一秒一次显示当前温度和湿度。注意处理好两个任务之间的数据共享。

void GetData(void* pdata)
{
    uint8_t buf[5];
    memset(buf, 0, sizeof(buf));
    while (1)
    {   //检验数据有效性
        if(DHT11_Read_Data(buf) == 1)
        {
            //温度+湿度
            ledValue = buf[2]*100 + buf[0];
        }

        Delay_ms(1000);
    }
}

void ShowData(void* pdata)
{
     while(1)
     {
         //由于传感器数据读取有1s间隔,数值能够稳定显示。
         display(ledValue);
         Delay_ms(5);
     }
}


在main函数前面,创建两个优先级为1和2的任务,由于读取数据的任务更重要,所以优先级更高。
int GetData_Task_STK[STK_Size];
int ShowData_Task_STK[STK_Size];
int main(){
    GPIO_Configuration();
    OSInit();
    OS_CPU_SysTickInit();
    OSTaskCreate(
        GetData,
        (void *)0,
        (OS_STK *)&GetData_Task_STK[STK_Size-1],
        1);
    OSTaskCreate(
        ShowData,
        (void *)0,
        (OS_STK *)&ShowData_Task_STK[STK_Size-1],
        2
    );
    OSStart();
    return 0;
}

                     下图为显示效果:



表明现在温度是26摄氏度,湿度为54%

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

69

主题

191

帖子

4

粉丝