uC/OS室温计

论坛 期权论坛 脚本     
匿名技术用户   2021-1-5 13:09   410   0

一、 实验目的和要求

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[i] = 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;

}

}

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[i] = Bit_SET;

}else{

v[i] = 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[i] = Bit_RESET;

}else{

v[i] = 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%


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP