ucos温度计


实验任务:

这个实验的目的是理解uC/OS II的任务调度方式,编写uC/OS II的应用程序,通过寄存 器直接操纵GPIO来驱动外 部设备。

实验步骤:

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

板卡:wrtnode

 

首先从github上下载ucos-ii-for-pcduino的代码,我们在此基础上做wrtnode的移植:

git clone https://github.com/Pillar1989/ucos-ii-for-pcDuino

1

下文中的”./”均指ucos-ii-for-pcDuino文件夹

其中 ./app存放我们的用户代码,我们稍候写的代码就放在./app/sample.c中。

./build存放编译的目标文件.o

./arduino 存放arduino库

./ucos存放ucos的源码

 

./config.mk存储编译的配置文件

./scp.sh 是我后来编写的脚本,主要是用scp命令拷贝二进制代码和必须的库到板卡上。

./Scp.sh文件的内容如下

2

ssh-keygen 命令用来删除之前预留的wrtnode指纹。因为我的板卡经常会被莫名其妙地reset重启并恢复出厂设置。(后来发现只要#GPIO2 引脚输出1就会reset)每次reset后指纹都会变更。linux默认会检验指纹,避免man-in-the-middle-attack(中间人攻击)。

Scp source destination 拷贝文件到板卡上。

ucos_sample是编译后的我们的二进制文件,剩余三个是程序运行时所需要的动态链接库,也需要一并拷贝到板卡上。

linux中,动态链接库以.so结尾,静态链接库以.a结尾(archive)

首先更改./arduino/makefile文件和./makefile文件,用mipsel-openwrt-linux-xxx工具链作交叉编译。
3

上图这样写的前提是我们已经把工具链编译程序放在了系统的path中,如果没有,请更改~/.bashrc文件并重启terminal。更改方法是,在~/.bashrc文件的末尾加上export PATH=”$PATH:[your crosstool-chain-directory]”
4

首先用交叉编译工具编译arduino库,它允许我们通过arduino函数的接口来调用gpio口。

./ Cd arduino

./arduino/make

5

然后退到上层目录,编译ucos和app程序。
6

编译期间(准确的说时链接期间)可能会遇到找不到xxx.so文件的情况,这时请在crosstool-chain的文件夹下用find指令找到该xxx.so文件,再在./config.mk 的LDFLAGS中添加该文件目录,这样链接器会在该文件目录下寻找动态库。语法为 -L[dir]
7

tips:用 nm xxx.so命令可以查看动态链接库中的label

编译成功后,会出现./ucos_sample文件,拷贝该文件和相关的动态链接库到板卡上,即可运行sample程序。

至此编译过程结束,下面开始编程。

wrtnode对GPIO的操作方面,不能直接用arduino库提供的pinMode等函数,因为它是为pcDuino所写,wrtnode和它还不太一样。我的解决方法是利用网上提供的一个wrtnode GPIO引脚中断的例程改编的,google wrtnode(or openwrt) + gpio + interrupt应该可以搜到,文件名为interrupt.c,我改成了gpio.c下图是代码的版权部分。
8

改段例程封装了wrtnode的gpio操作,但每次操作gpio口很费时,需要100us左右。因为实验中用到的DHT11的数据输出时也是以us级别来输出总线数据,所以在代码中我直接用了

lseek(fd, 0, SEEK_SET);

read(fd, &bit, 1);

来读取gpio对应的fd的数据,这样每次读数据的时间缩短在26us左右.

 

DHT11读取温度湿度,根据它的datasheet来编程。http://wenku.baidu.com/view/1955cc70a417866fb84a8e7b.html

 

四位七段数码管要用分时复用来编程。我一开始尝试用完全分时的28段分时编程,结果频闪过于严重,惨不忍睹。权衡之下采用了4段分时编程。

 

 

 

以下是代码片段,直接改的sample.c,版权信息没删。

/*

*********************************************************************************************************

*                                               sample.c

*

* Description:      This sample program uses the ucos linux port to start 5 simple tasks.

*

* Author: Philip Mitchell

*

*********************************************************************************************************

*/

 

#include <stdio.h>

#include <stdlib.h>

#include “ucos_ii.h”

#include <core.h>

#include <string.h>

 

void showDigit(uint8_t* digits);

 

uint8_t led_pins_slice[] = {41, 21, 0, 18};//gpio 2 can not use, cause reset

uint8_t led_pins_segment[] = {43, 72, 37, 19, 17, 40, 42, 44};

int32_t led_pins_slice_fd[4];

int32_t led_pins_segment_fd[8];

uint8_t data_pin = 20;

uint8_t data[5];

uint8_t dataAvailable = 0;

void hardware_init()

{

//set slice pins

uint8_t i = 0;

for (i = 0; i < 4; ++i)

{

gpio_export(led_pins_slice[i]);

gpio_set_dir(led_pins_slice[i], OUTPUT);

gpio_set_value(led_pins_slice[i], LOW);

led_pins_slice_fd[i] = gpio_fd_open(led_pins_slice[i]);

}

 

//set segment pins

for (i = 0; i < 8; ++i)

{

gpio_export(led_pins_segment[i]);

gpio_set_dir(led_pins_segment[i], OUTPUT);

gpio_set_value(led_pins_segment[i], HIGH);

led_pins_segment_fd[i] = gpio_fd_open(led_pins_segment[i]);

}

 

//set data pin

gpio_export(data_pin);

gpio_set_dir(data_pin, OUTPUT);

gpio_set_value(data_pin, HIGH);

}

/* Function common to all tasks */

 

void controlLed(void *p_arg){

#if OS_CRITICAL_METHOD == 3

OS_CPU_SR     cpu_sr = 0;

#endif

uint8_t i;

while(1){

//OS_ENTER_CRITICAL();

uint8_t values[] = {0,0,0,0};

if(dataAvailable){

values[0] = data[2] / 10;

values[1] = data[2] % 10;

values[2] = data[0] / 10;

values[3] = data[0] % 10;

}

showDigit(values);

//OS_EXIT_CRITICAL();

}

}

void showDigit(uint8_t* digits){

//slice between 0 ~ 3

//digit between 0 ~ 9

uint8_t matrix[] = {0xD7, 0x14, 0xCD, 0x5D, 0x1E,

0x5B, 0xDB, 0x15, 0xDF, 0x5F};

uint8_t i;

uint8_t j;

for(i = 0; i < 4; i++){

//close led

for(j = 0; j < 4; j++){

gpio_set_value(led_pins_slice[j], LOW);

}

//set segment

for(j = 0; j < 8; j++){

uint8_t value = !(matrix[digits[i]] & (0x80 >> j));

gpio_set_value(led_pins_segment[j], value);

}

//chose slice

for(j = 0; j < 4; j++){

if(i == j){

gpio_set_value(led_pins_slice[j], HIGH);

}

else{

gpio_set_value(led_pins_slice[j], LOW);

}

}

 

OSTimeDly(1);

}

 

}

void readData( void *p_arg )

{

char* sTaskName = (char*)p_arg;

uint8_t bit;//bit value

uint8_t isError = 0;

uint32_t t;

uint8_t bitIndex, byteIndex;

uint8_t byte;

uint32_t i;

uint32_t timeCnt;

//     static flag1 = 1;

#if OS_CRITICAL_METHOD == 3

OS_CPU_SR     cpu_sr = 0;

#endif

 

//wait 1s for DHT11 to warm up — OK

OSTimeDly(201);

int fd = gpio_fd_open(data_pin);

 

while(1)

{

isError = 0;

gpio_set_dir(data_pin, OUTPUT);

gpio_set_value(data_pin, HIGH);

OSTimeDly(201);

OS_ENTER_CRITICAL();

//send start signal to DHT11

gpio_set_value(data_pin, LOW);

delay(20);//send low signal longer than 18ms, avarage 29ms — OK

gpio_set_dir(data_pin, INPUT); //140us

 

lseek(fd, 0, SEEK_SET);

read(fd, &bit, 1);

 

//get ack bit

timeCnt = 10000;

while(bit != LOW){

//gpio_get_value(data_pin, &bit);

lseek(fd, 0, SEEK_SET);

read(fd, &bit, 1);

bit -= ‘0’;

if(–timeCnt == 0){// 200us

isError = 1;

printf(“didn\’t receive LOW ack from DHT11.\n”);

break;

}

}

if(isError == 1){

continue;

}

 

//receive ack from DHT11

// t = micros();

timeCnt = 10000;

while(bit != HIGH){

//gpio_get_value(data_pin, &bit);

lseek(fd, 0, SEEK_SET);

read(fd, &bit, 1);

bit -= ‘0’;

if(–timeCnt == 0){// 2000us

isError = 1;

printf(“didn\’t receive HIGH ack from DHT11.\n”);

break;

}

}

if(isError == 1){

continue;

}

 

timeCnt = 10000;

while(bit != LOW){

lseek(fd, 0, SEEK_SET);

read(fd, &bit, 1);

bit -= ‘0’;

if(–timeCnt == 0){// 2000us

isError = 1;

printf(“didn\’t receive LOW gap from DHT11.\n”);

break;

}

}

if(isError == 1){

OS_EXIT_CRITICAL();

continue;

}

//omit some codes here…

//…

OS_EXIT_CRITICAL();

}

 

}

 

 

int main (void)

{

/* pthreads allocates its own memory for task stacks. This UCOS linux port needs a minimum stack size

in order to pass the function information within the port. */

hardware_init();

INT8U Stk1[ OSMinStkSize() ];

INT8U Stk2[ OSMinStkSize() ];

INT8U Stk3[ OSMinStkSize() ];

INT8U Stk4[ OSMinStkSize() ];

INT8U Stk5[ OSMinStkSize() ];

 

char sTask1[] = “Task 1”;

char sTask2[] = “Task 2”;

char sTask3[] = “Task 3”;

char sTask4[] = “Task 4”;

//     char sTask5[] = “Task 5”;

 

OSInit();

//delay 1s for DHT11 to warm up.

OSTaskCreate( readData, sTask1, (void*)Stk1, 0 );

OSTaskCreate( controlLed, sTask2, (void*)Stk2, 5 );

//     OSTaskCreate( MyTask, sTask3, (void*)Stk3, 6 );

//     OSTaskCreate( MyTask, sTask4, (void*)Stk4, 7 );

//     OSTaskCreate( MyTask, sTask5, (void*)Stk5, 8 );

 

OSStart();

 

return 0;

}

 

前两位是温度26,后两位是湿度63

9

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.