瑞萨单片机论坛
直播中

张帆

8年用户 70经验值
擅长:处理器/DSP,控制/MCU,RF/无线
私信 关注

【RA4M2设计挑战赛】基于RA4M2的物联网网关2--RAM4M2+DA16200实现物联网网关

RA4M2设计挑战赛

功能概述

经过一段时间的探索,终于完成了一个基础版本的物联网网关。

物联网网关主要实现了以下功能:

采集HS3003的数据,获取温湿度,然后通过串口和DA16200 将数据使用mqtt协议发送到mqtt服务器上。整体的框图如下:

image.png

硬件连接图

整体连接如下图所示:

整体连接图1.jpg![整体连接图1.jpg]

其中,1处为开发板的I2C座子,和HS3003引脚正好对应,直接插上。2处为SWD口,一开始我使用CHLINKE连接,一直下载不进去程序,后来看到了群里小伙伴用stlink可以下载,就去某宝10几块买了一个,结果还真的能下载。不过要注意的是,stlink如果下载时无法识别型号,需要下载个STM32CubeProgrammer软件,更新下固件,就可以下载了。stlink的具体配置如下图:

image.png

image.png

3处为PMOD2口,这个PMOD口其实也就是串口,此处使用的uart0,将DA16200直接插上去即可,具体怎么连接可以参考我上一篇帖子。

4处也就是这个开发板的uart9了,这了自带了一个ch340,因此我们用这个串口来打印日志,来实现调试。

软件部分

想要完成这个物联网网关,需要满足两点:

1.代码编写

2.mqtt服务器

其中代码编写我放在后面说,主要说下mqtt服务器。

由于调试的有点晚了,阿里云需要审核3几天的审核时间,因此,我使用了然也物联的公用mqtt服务器,http://www.ranye-iot.net/,这个服务器配置还挺简单。

电脑端mqtt客户端我选择了mqtt.fx1.7.1,这个版本时免费的,后续的版本就要收费了。

还有就是mqtt协议的学习,我是跟着bilibili的[太极创客]老师学的,这老师讲的真心不错,通俗易懂,推荐学习mqtt的同学去听一下。

mqtt.fx1.7.1的安装我就不讲了,一直下一步就好了,主要讲下怎么配置。

因为我们目前只实现一个简单的mqtt收发,因此配置是很简单的,如下图所示:

image.png

其中,2为任务名,3为然也公用mqtt服务器的地址,4为client-id,client-id最好起一个不容易重复的,因为这是个公用服务器,重复的id可能会连接失败。

代码部分

代码部分,我参考了demo中的代码,进行了少量的修改,主要功能点代码有:

hs3003.c,这里主要实现了对i2c的初始化和启动,以及回调函数的编写,而具体获取温湿度值放在了wifidemo中,每获取一条记录,就会向mqtt发送数据

void g_comms_i2c_bus0_quick_setup(void)
{
    fsp_err_t err;
    err = R_SCI_I2C_Open(&hs3003_i2c3_ctrl, &hs3003_i2c3_cfg);
    assert(FSP_SUCCESS == err);
}


void hs3003_i2c_callback(i2c_master_callback_args_t * p_args)
{
	  if (HS3003_CALLBACK_STATUS_SUCCESS == p_args->event)
    {
        hs3003_callback_status = HS3003_CALLBACK_STATUS_SUCCESS;
    }
    else
    {
        hs3003_callback_status = HS3003_CALLBACK_STATUS_REPEAT;
    }
}

bap_uart.c,这里主要实现了对printf/scanf函数的重写,每次printf都会向uart9发数据

#include "bsp_debug_uart.h"
/* 调试串口 UART4 初始化 */
void bsp_uart_init(void)
{
	fsp_err_t err = FSP_SUCCESS;
	err = R_SCI_UART_Open (&debug_uart_ctrl, &debug_uart_cfg);
	assert(FSP_SUCCESS == err);
}

/* 发送完成标志 */
volatile bool uart_send_complete_flag = false;
volatile bool uart_recv_complete_flag = false;
volatile uint32_t uart_recv_char = '\0';
/* 串口中断回调 */

void debug_uart_callback (uart_callback_args_t * p_args)
{
	switch (p_args->event)
	{
		case UART_EVENT_RX_CHAR:
		{
		// 把串口接收到的数据发送回去
		R_SCI_UART_Write(&debug_uart_ctrl, (uint8_t *)&(p_args->data), 1);
		break;
		}
		case UART_EVENT_TX_COMPLETE:
		{
		uart_send_complete_flag = true;
		break;
		}
		default:
		break;
	}
}

/*
void debug_uart_callback(uart_callback_args_t * p_args)
{
	if (p_args->event == UART_EVENT_TX_COMPLETE)
	{
		uart_send_complete_flag = true;
	}
	else if (p_args->event == UART_EVENT_RX_CHAR)
	{
		uart_recv_char = p_args->data;
		uart_recv_complete_flag = true;
	}
}
*/
/* 重定向 printf 输出 */
#if defined __GNUC__ && !defined __clang__
int _write(int fd, char *pBuffer, int size); //防止编译警告
int _write(int fd, char *pBuffer, int size)
{
	(void)fd;
	R_SCI_UART_Write(&g_uart0_ctrl, (uint8_t *)pBuffer, (uint32_t)size);
	while(uart_send_complete_flag == false);
	uart_send_complete_flag = false;
	return size;
}
#else
int fputc(int ch, FILE *f)
{
	(void)f;
	R_SCI_UART_Write(&debug_uart_ctrl, (uint8_t *)&ch, 1);
	while(uart_send_complete_flag == false);
	uart_send_complete_flag = false;
	return ch;
}

int fgetc(FILE *f) 
{	
	(void)f;
	
	while (uart_recv_complete_flag == false)
	{}
	uart_recv_complete_flag = false;

	return (int)uart_recv_char;
}

da16200AT.c

这个文件中主要定义了所有wifi设置,初始化,mqtt设置,收发订阅所要用到的AT命令,以及AT命令发送函数等,基本也是照着官方demo改几个字段就好了。由于文件太长,此处就只粘贴主要命令了。

da16200_at_cmd_set_t g_da16200_cmd_set[] =
{
    /** Intial AT command */
    [DA16200_AT_CMD_INDEX_ATZ] =
    {
        .p_cmd = (uint8_t *) "ATZ\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_10,
        .retry_delay = DA16200_DELAY_500MS
    },
    /** Echo on/ off */
    [DA16200_AT_CMD_INDEX_ATE] =
    {
        .p_cmd = (uint8_t *) "ATE\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* ATF */
    [ DA16200_AT_CMD_INDEX_AT_ATF] =
    {
        .p_cmd = (uint8_t *) "ATF\r\n",
        .p_success_resp = (uint8_t *) "DONE",
        .max_resp_length = DA16200_STR_LEN_128,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_500MS
    },
    /* Set boot mode */
    [DA16200_AT_CMD_INDEX_AT_TMRFNOINIT] =
    {
        .p_cmd = (uint8_t *) "AT+TMRFNOINIT=0\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* Set Station mode */
    [DA16200_AT_CMD_INDEX_AT_WFMODE] =
    {
        .p_cmd = (uint8_t *) "AT+WFMODE=0\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* Restart */
    [ DA16200_AT_CMD_INDEX_AT_RESTART] =
    {
        .p_cmd = (uint8_t *) "AT+RESTART\r\n",
        .p_success_resp = (uint8_t *) "DONE",
        .max_resp_length = DA16200_STR_LEN_128,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_1000MS
    },
    /* 连接wifi热点 */
    [DA16200_AT_CMD_INDEX_AT_WFJAP] =
    {
        .p_cmd = (uint8_t *) "AT+WFJAP=35_102,4,1,990351102\r\n",
        .p_success_resp = (uint8_t *) "+WFJAP:1",
        .max_resp_length = DA16200_STR_LEN_128,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_2000MS
    },
    /* TCP连接 */
    [DA16200_AT_CMD_INDEX_AT_TRTC] =
    {
        .p_cmd = (uint8_t *) "AT+TRTC=192.168.0.103,8000\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_128,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_1000MS
    },
    /* 发送数据 */
    [DA16200_AT_CMD_INDEX_AT_SEND_DATA] =
    {
        .p_cmd = (uint8_t *) "AT+WFMODE=0\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_512,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_1000MS
    },


    /* Set Country Code */
    [DA16200_AT_CMD_INDEX_AT_WFCC] =
    {
        .p_cmd = (uint8_t *) "AT+WFCC=CH\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* Set Country Code */
    [ DA16200_AT_CMD_INDEX_AT_WFSAP] =
    {
        .p_cmd = (uint8_t *) "AT+WFSAP=Renesas_Wifi,3,1,12345678,1,CH\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_128,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* Set IP */
    [ DA16200_AT_CMD_INDEX_AT_NWIP] =
    {
        .p_cmd = (uint8_t *) "AT+NWIP\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_1000MS
    },
    /* Start DHCP */
    [ DA16200_AT_CMD_INDEX_AT_NWDHS] =
    {
        .p_cmd = (uint8_t *) "AT+NWDHS=1\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* DHCP IP area set*/
    [ DA16200_AT_CMD_INDEX_AT_NWDHR] =
    {
        .p_cmd = (uint8_t *) "AT+NWDHR=192.168.10.3,192.168.10.10\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* TCP server port set*/
    [ DA16200_AT_CMD_INDEX_AT_TRTS] =
    {
        .p_cmd = (uint8_t *) "AT+TRTS=80\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* TCP server port message save */
    [ DA16200_AT_CMD_INDEX_AT_TRSAVE] =
    {
        .p_cmd = (uint8_t *) "AT+TRSAVE\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
        /* 查看IP地址 */
    [ DA16200_AT_CMD_INDEX_AT_NWIP1] =
    {
        .p_cmd = (uint8_t *) "AT+NWIP\r\n",
        .p_success_resp = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /**********************  MQTT ****************************/
    /*  MQTT Enable/Disable the MQTT client  */
    [ DA16200_AT_CMD_INDEX_AT_NWMQTCL ] =
    {
        .p_cmd = (uint8_t *) "AT+NWMQCL=1\r\n",
    .p_success_resp = (uint8_t *) "OK",
    .max_resp_length = DA16200_STR_LEN_128,
    .retry = DA16200_RETRY_VALUE_5,
    .retry_delay = DA16200_DELAY_200MS
    },
    /*  Set the host name(or IP address and the port numberof the MQTT Broker  */
    [ DA16200_AT_CMD_INDEX_AT_NWMQBR ] =
    {
        .p_cmd = (uint8_t *) "AT+NWMQBR=test.ranye-iot.net,1883\r\n",
    .p_success_resp = (uint8_t *) "OK",
    .max_resp_length = DA16200_STR_LEN_64,
    .retry = DA16200_RETRY_VALUE_5,
    .retry_delay = DA16200_DELAY_500MS
    },
    /*  Set MQTT subscrpt  */
    [ DA16200_AT_CMD_INDEX_AT_NWMQTS ] =
    {
        .p_cmd = (uint8_t *) "AT+NWMQTS=1,simon-zf\r\n",
    .p_success_resp = (uint8_t *) "OK",
    .max_resp_length = DA16200_STR_LEN_64,
    .retry = DA16200_RETRY_VALUE_5,
    .retry_delay = DA16200_DELAY_500MS
    },

    /*  Set MQTT pubscrpt  */
    [ DA16200_AT_CMD_INDEX_AT_NWMQTP ] =
    {
        .p_cmd = (uint8_t *) "AT+NWMQTP=simon-zfpub\r\n",
    .p_success_resp = (uint8_t *) "OK",
    .max_resp_length = DA16200_STR_LEN_64,
    .retry = DA16200_RETRY_VALUE_5,
    .retry_delay = DA16200_DELAY_500MS
    },
    /*  Set MQTT pub msg  */
    [ DA16200_AT_CMD_INDEX_AT_NWMQMSG ] =
    {
        .p_cmd = (uint8_t *) "AT+NWMQMSG=simon test\r\n",
    .p_success_resp = (uint8_t *) "OK",
    .max_resp_length = DA16200_STR_LEN_64,
    .retry = DA16200_RETRY_VALUE_5,
    .retry_delay = DA16200_DELAY_500MS
    }


};

dialog_wifi_demo.c

这个模块是在官方的demo基础上改的,基本上流程如下:

image.png

具体代码如下:

/************************************************************************************
* Name:       dialog_wifi_demo
* Function:   run dialog wifi demo
* Parameters: none
* Return:     none
************************************************************************************/
void dialog_wifi_demo(void)
{

//    http_receive_status http_status;
    static unsigned char operation = 0;
    static uint8_t cnt=0;
    fsp_err_t err;

    uint8_t r_buf[4] = {0};
    uint16_t humi, temp;
    float    tmp_f   = 0.0;
    float    tmp_f2  = 0.0;
	uint8_t data[2] = {0x00,0x00};
	demo_sequence_t         sequence = DEMO_SEQUENCE_1;

   while(1)
   {
       switch(operation)
       {
           case 0:
                //Wi-Fi initializatoin
                g_ioport.p_api->pinWrite(g_ioport.p_ctrl, LED1, BSP_IO_LEVEL_HIGH);
                printf("begin wifi init succes!\r\n");
                wifi_init();
                //Wi-Fi setting
                 printf("begin wifi set succes!\r\n");
                err = wifi_set();
		       printf("wifi set succes!\r\n");
               err = wifi_mqtt_set();
               	printf("mqtt set succes!\r\n");
                	g_comms_i2c_bus0_quick_setup();
                printf("i2c set succes!\r\n");
                g_ioport.p_api->pinWrite(g_ioport.p_ctrl, LED1, BSP_IO_LEVEL_LOW);
                if(err)
                {
                    R_BSP_SoftwareDelay(2000,BSP_DELAY_UNITS_MILLISECONDS);
                }
                else
                {
                    R_BSP_SoftwareDelay(2000,BSP_DELAY_UNITS_MILLISECONDS);
                    operation = 1;
                }
                break;

           case 1:
               cnt++;
               //memset (user_buffer, " " , sizeof(user_buffer));
               //sprintf((char *)user_buffer,"%s%s%3d%s",(char *)AT_S,(char *)TCP_DATA,(uint8_t)cnt,"}\r\n");
               //err = wifi_TCP_SEND_DATA();
                printf("cal tmp and humi\r\n");
                err = R_SCI_I2C_Write(&hs3003_i2c3_ctrl,data,1,0);
                R_BSP_SoftwareDelay(40000,BSP_DELAY_UNITS_MICROSECONDS);
                err = R_SCI_I2C_Read(&hs3003_i2c3_ctrl,&r_buf,4,1);
                if(err == FSP_SUCCESS)
                {
                printf("0x%X,0x%X,0x%X,0x%X\n", r_buf[0], r_buf[1], r_buf[2], r_buf[3]);
                printf("state:%x\n", r_buf[0] & RM_HS300X_MASK_STATUS_0XC0);
                if ((r_buf[0] & RM_HS300X_MASK_STATUS_0XC0) != RM_HS300X_DATA_STATUS_VALID)
                {
                    printf("转换时间不哆");
                }

                humi = (r_buf[0] & RM_HS300X_MASK_HUMIDITY_UPPER_0X3F) << 8 | r_buf[1];
                temp = (r_buf[2] << 8 | (r_buf[3] & RM_HS300X_MASK_TEMPERATURE_LOWER_0XFC)) >> 2;

                tmp_f = (float)humi;
                tmp_f = (tmp_f * RM_HS300X_CALC_HUMD_VALUE_100) / RM_HS300X_CALC_STATIC_VALUE;
                        printf("humi: %.2f\n",tmp_f );

                tmp_f2 = (float)temp;
                tmp_f2 = ((tmp_f2 * RM_HS300X_CALC_TEMP_C_VALUE_165) / RM_HS300X_CALC_STATIC_VALUE) - RM_HS300X_CALC_TEMP_C_VALUE_40;
                        printf("temp: %.2f\n", tmp_f2);
                }
                printf("begin mqtt\r\n");
                sprintf((char *)user_buffer,"AT+NWMQMSG=humi: %.2f--temp:%.2f\n",tmp_f,tmp_f2);

                g_da16200_cmd_set[DA16200_AT_CMD_INDEX_AT_NWMQMSG].p_cmd = user_buffer;
                               printf("AT:%s",user_buffer);
               TEST();
               if(err)
               {
                   cnt--;
                   R_BSP_SoftwareDelay(2000,BSP_DELAY_UNITS_MILLISECONDS);
                   operation = 0;
               }
               else
               {
                   R_BSP_SoftwareDelay(1000,BSP_DELAY_UNITS_MILLISECONDS);
                   g_ioport.p_api->pinWrite(g_ioport.p_ctrl, LED2, BSP_IO_LEVEL_HIGH);
                   R_BSP_SoftwareDelay(1000,BSP_DELAY_UNITS_MILLISECONDS);
                   g_ioport.p_api->pinWrite(g_ioport.p_ctrl, LED2, BSP_IO_LEVEL_LOW);
               }
               break;
           default:
               operation = 0;
               break;
       }
   }
}

以上就是代码部分了,最终实现的效果见置顶视频,即在mqtt.fx软件中可以实时看到采集的数据。

工程代码如下:

*附件:FSP_Project2.rar

任务感受

这个任务做到现在,只实现了最基础的一个mqtt服务器收发的网关。但在这个任务过程中,我学了挺多东西,包括keil工程的建立,FSP包的使用,以及DA16200的使用,还有mqtt协议。这是个非常大的收获。在这过程中,也多亏了·群里大佬的帮助,大佬写的文章给了我很多帮助,例如程序下载,激活DA16200等,在此向大佬表示感谢。

最后,这个任务还有很多优化的地方,比如增加mqtt服务器和客户端的交互,增加服务器收到数据的处理流程,以及增加采集的数据传感器等。这个我预计这周能完善下,现在先把任务提交下。

更多回帖

发帖
×
20
完善资料,
赚取积分