玩转RT-Thread系列教程(11)--综合485通信+文件系统综合实战

Posted Rb菌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了玩转RT-Thread系列教程(11)--综合485通信+文件系统综合实战相关的知识,希望对你有一定的参考价值。

玩转RT-Thread系列教程(11)–综合485通信+文件系统综合实战

根据前两篇文章我们学习了485总线读取温湿度数据+虚拟文件系统的使用,今天让我们来结合二者进行一次综合实战

一、案例分析

  • 1.挂载SD卡
  • 2.获取温湿度数据
  • 3.在创建SD卡中创建文件,保存数据
  • 4.将异常温湿度数据保存到SD文件中

二、系统优化

在进行我们今天的综合案例前,我们先对我们之前的代码进行优化

1.SD热插处理

void FlieSystem_entry(void *parameter)
{
    static rt_err_t result;

    rt_device_t dev;

    while(1)
    {
        dev = rt_device_find("sd0");

        if (dev != RT_NULL)
        {
            if (dfs_mount("sd0", "/", "elm", 0, 0) == RT_EOK)
            {
                rt_kprintf("SD mount to / success\\n");
                break;
            }
            else
            {
                rt_kprintf("SD mount to / failed\\n");
            }
        }
        rt_thread_mdelay(500);
    }
}

static int FileSystemInit(void)
{
    //创建sd线程
    rt_thread_t thread_filesystem = rt_thread_create("file_sys", FlieSystem_entry, RT_NULL, 1024, 18, 20);

    if (thread_filesystem != RT_NULL)
    {
        rt_thread_startup(thread_filesystem);
    }
}

INIT_ENV_EXPORT(FileSystemInit);

2.温湿度数据发送

之前我们读取到的温湿度数据都是直接打印出来或者通过全局变量进行处理,这对于简单的工程我们是可以接受的,但对于复杂的功能来说,我们需要进行线程之间的通信来获取其他线程的数据。这里就用到了我们之前学习到的消息邮箱机制。

发送线程:

接收线程:

通过永久等待方式等待邮箱消息的来到。

3.创建ADC处理线程

三、案例实战

1.文件的读写操作

这里我操作文件使用的是POSIX方式

//保存数据到SD
void Sensor_DataTo_SD(char* buff)
{
    /* 以创建和读写模式打开 /text.txt 文件,如果该文件不存在则创建该文件 */
    FILE *recvdata_p0;
    recvdata_p0 = fopen("/Sensor_Data.cav", "a+");
    if (recvdata_p0 != RT_NULL)
    {
        fputs(buff, recvdata_p0);
        fputs("\\n", recvdata_p0);
        fclose(recvdata_p0);
    }
}

//从SD读取信息
void Data_ReadFSD(void)
{
    FILE *fp;
    char buffer[120];
    fp = fopen("/Sensor_Data.cav", "r");
    if (fp != RT_NULL)
    {
        fread(buffer, sizeof(char), sizeof(buffer), fp);
        rt_kprintf("%s", buffer);
        fclose(fp);
    }
}

2.温度阈值判断逻辑

判断阈值逻辑我是这样写的,当超过最高/低设定阈值时,通过累加器去进行累加,当超过一定次数便真正进行警报处理

void Save_Data_TOSD(float data1, float data2)
{
    if(data1 >= HIGHT_TEMPVALUE)
    {
        detect_logic.T_Count_Alarm++;
    }
    else
		{
			detect_logic.T_Count_Alarm--;
			if(detect_logic.T_Count_Alarm <= 0)
				detect_logic.T_Count_Alarm = 0;
		}
		if(detect_logic.T_Count_Alarm >= MAX_COUNTER)
		{
				detect_logic.T_Count_Alarm = MAX_COUNTER;
				rt_kprintf("温度超过标准!%d\\n",detect_logic.T_Count_Alarm);
				sprintf((char*)detect_logic.Alarm_buff, "Temp:%.2f,humi:%.2f", data1, data2); //拼接到温度数组里
				//保存异常数据到SD卡
				Sensor_DataTo_SD((char*)detect_logic.Alarm_buff);
		}
		//
    if(data2 >= HIGHT_HUMIVALUE)
    {
        detect_logic.H_Count_Alarm++;
    }
    else
		{
			detect_logic.H_Count_Alarm--;
			if(detect_logic.H_Count_Alarm <= 0)
				detect_logic.H_Count_Alarm = 0;
		}

		if(detect_logic.H_Count_Alarm >= MAX_COUNTER)
		{
				detect_logic.H_Count_Alarm = MAX_COUNTER;
				rt_kprintf("湿度超过标准!%d\\n",detect_logic.H_Count_Alarm);
				sprintf((char*)detect_logic.Alarm_buff, "Temp:%.2f,humi:%.2f", data1, data2); //拼接到温度数组里
				//保存异常数据到SD卡
				Sensor_DataTo_SD((char*)detect_logic.Alarm_buff);
		}
}

3.利用事件进行线程同步

既然利用到了事件,那么我们先来介绍一下事件集的作用以及用法:

3.1、事件的介绍

3.2、事件在系统中的使用

因为我们分别有ADC线程,温湿度获取线程等多个线程,假设一个线程采集数据很快,另一个线程采集速度很慢,那么假设我们不使用线程间同步方式进行处理的话,很容易会导致数据的不一致性。所以我们使用事件方式来处理线程之间的同步。

4.接收线程处理

在接收线程中,这里我参考了WillianChan在分布式温度监控系统中对接收数据线程的方法,使用一个永久等待接收的事件以及超时接收事件来优化文件存储耗时的问题——只有当超过阈值时才进行数据的转存。

static void Publish_th(void *pram)
{
    //传感器数据结构体
    Sensor_msg sensor_msg;
    static rt_uint32_t e;
    static char r_buff[64];

    while(1)
    {
        if (rt_event_recv(Sensor_event, EVENT_ADC_FLAG, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &e) != RT_EOK)
            continue;

				//2000ms超时接收 --- 
        if (rt_event_recv(Sensor_event, EVENT_TH_FLAG, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, rt_tick_from_millisecond(2000), &e) == RT_EOK)
        {
            //永久等待接收邮件
            if(rt_mb_recv(Sensor_msg_mb, (rt_ubase_t*)&sensor_msg, RT_WAITING_FOREVER) == RT_EOK)
            {
                sprintf((char*)r_buff, "Temp:%.2f,humi:%.2f", (float)sensor_msg->temp, (float)sensor_msg->hum); //拼接到温度数组里
            }
						//ringbuffer缓存数据
//						rt_ringbuffer_put(recvdatabuf, (rt_uint8_t *)r_buff, strlen((const char*)r_buff));
						
            rt_kputs((char*)r_buff);
            rt_kputs("\\n");
						
						//阈值判断逻辑
						Save_Data_TOSD((float)sensor_msg->temp, (float)sensor_msg->hum);
						
            //释放内存块
            rt_mp_free(sensor_msg);
            sensor_msg = RT_NULL;
						continue;
        }
				//1s超时直接存数据
				//阈值判断逻辑
				rt_kputs("@1s接收事件超时--存储数据\\n");
				Sensor_DataTo_SD((char*)r_buff);
    }
}

5.编译、下载、验证

可以看到,当湿度超过阈值时,异常数据才会被保存到excell文档中。

以上是关于玩转RT-Thread系列教程(11)--综合485通信+文件系统综合实战的主要内容,如果未能解决你的问题,请参考以下文章

玩转RT-Thread系列教程文章资源汇总

玩转RT-Thread系列教程(10)--文件系统使用

玩转RT-Thread系列教程(10)--文件系统使用

玩转RT-Thread系列教程--消息邮箱的使用

玩转RT-Thread系列教程--移植STemwin

玩转RT-Thread系列教程--线程的使用