硬件连接 i2c1 连接 AM2320温湿度传感器。
i2c0 连接 GY30-BH1750光强传感器。
用到两个库
一个是paho.mqtt.embedded-c-master.zip github上维护的c语言版本的mqtt协议库。链接
另一个是 博通的io操作库 bcm2835-1.68.tar.gz 链接
我的工程里并没有编译成so,我直接把源码里用的c文件复制过来了。
还有bcm2835 库有个宏 定义了i2c1 ,默认i2c0 是不编译的,我用了i2c0,库函数让我改了。
AM2320 读取函数
int get_am2320_data(int *temperature,int *himudity)
{
uint8_t w_temp_data[AM2320_CMD_LEMGTH] = {0};
uint8_t r_temp_data[AM2320_TEMP_RETURN_LENGTH] = {0};
iot_info("run get data from am2320\n");
if (!bcm2835_init())
{
iot_error("bcm2835_init failed. Are you running as root??\n");
return FAILURE;
}
if (!bcm2835_i2c_begin(I2C_1))
{
iot_error("bcm2835_i2c_begin failed. Are you running as root??\n");
return FAILURE;
}
bcm2835_i2c_setSlaveAddress(I2C_1,AM2320_DEVICE_ADDR);
bcm2835_i2c_set_baudrate(I2C_1,AM2320_BAUDRATE);
bcm2835_i2c_write(I2C_1,NULL,0); //wark up
usleep(30*1000);
w_temp_data[0] = AM2320_FUNCTION_CODE;
w_temp_data[1] = AM2320_TEMP_HUMIDITY_ADDR;
w_temp_data[2] = AM2320_TEMP_HUMIDITY_LENGTH;
bcm2835_i2c_write(I2C_1,w_temp_data,AM2320_CMD_LEMGTH);
usleep(30*1000);
bcm2835_i2c_read(I2C_1,r_temp_data,AM2320_TEMP_RETURN_LENGTH);
*himudity = (((r_temp_data[2] << 8) | (r_temp_data[3])) & 0xffff);
*temperature = (((r_temp_data[4] << 8)| (r_temp_data[5])) & 0xffff);
bcm2835_i2c_end(I2C_1);
bcm2835_close();
return SUCCESS;
}
BH1750 读取函数
int get_light_value(uint16_t *light_value)
{
uint8_t r_light_data[2] = {0};
uint8_t high_mode = BH_HMODE_RESOLUTION;
iot_info("get_light_value now\n");
if (!bcm2835_init())
{
iot_error("bcm2835_init failed. Are you running as root??\n");
return FAILURE;
}
if (!bcm2835_i2c_begin(I2C_0))
{
iot_error("bcm2835_i2c_begin failed. Are you running as root??\n");
return FAILURE;
}
bcm2835_i2c_setSlaveAddress(I2C_0,BH1750_DEVICE_ADDR);
bcm2835_i2c_set_baudrate(I2C_0,BH1750_BAUDRATE);
bcm2835_i2c_write(I2C_0,&high_mode,1);
usleep(180 * 1000);
bcm2835_i2c_read(I2C_0,r_light_data,2);
bcm2835_i2c_end(I2C_0);
bcm2835_close();
*light_value = ((r_light_data[0] << 8) | r_light_data[1]);
return SUCCESS;
}
int init_bh1750()
{
uint8_t power_on = BH_POWER_ON;
uint8_t reset = BH_RESET;
iot_info("init_bh1750 now\n");
if (!bcm2835_init())
{
iot_error("bcm2835_init failed. Are you running as root??\n");
return FAILURE;
}
iot_info("init_bh1750 now\n");
if (!bcm2835_i2c_begin(I2C_0))
{
iot_error("bcm2835_i2c_begin failed. Are you running as root??\n");
return FAILURE;
}
bcm2835_i2c_setSlaveAddress(I2C_0,BH1750_DEVICE_ADDR);
bcm2835_i2c_set_baudrate(I2C_0,BH1750_BAUDRATE);
bcm2835_i2c_write(I2C_0,&power_on,1);
usleep(10 * 1000);
bcm2835_i2c_write(I2C_0,&reset,1);
bcm2835_i2c_end(I2C_0);
bcm2835_close();
return SUCCESS;
}
还有个问题,我在几个线程里操作 博通这个库,如果抢占资源,会出现段错误,所以要保证一个时间点只要一个线程去操作博通这个库。这里用到了线程锁。
void *get_sensor_data_function(void *arg)
{
int temp;
int himudity;
uint16_t light_value;
int ret = 0;
pthread_mutex_lock(&m_mutex);
init_bh1750();
pthread_mutex_unlock(&m_mutex);
while (1){
cJSON * root = cJSON_CreateObject();
cJSON * item = cJSON_CreateObject();
pthread_mutex_lock(&m_mutex);
get_am2320_data(&temp,&himudity);
pthread_mutex_unlock(&m_mutex);
pthread_mutex_lock(&m_mutex);
get_light_value(&light_value);
pthread_mutex_unlock(&m_mutex);
//iot_info("get_am2320_data temp = %d himudity = %d\n",temp,himudity);
//iot_info("get_bh1750_data light = %d\n",light_value);
//iot_info("get ali connect status = %s\n",Iot_mqtt.iotstatus == IOT_STATUS_CONNECT ? "Connect" : "Disconect");
cJSON_AddItemToObject(root,"method",cJSON_CreateString("thing.event.property.post"));
cJSON_AddItemToObject(root,"id",cJSON_CreateString("01406633"));
cJSON_AddItemToObject(root,"params",item);
cJSON_AddItemToObject(item,"RoomTemp",cJSON_CreateNumber((float)temp/10.0));
cJSON_AddItemToObject(item,"RoomHumidity",cJSON_CreateNumber((float)himudity/10.0));
cJSON_AddItemToObject(item,"RoomLight",cJSON_CreateNumber((light_value * 10)/12));
cJSON_AddItemToObject(root,"version",cJSON_CreateString("1.0.0"));
char *payload_data = cJSON_Print(root);
//iot_info("payload data = %s\n",payload_data);
if (Iot_mqtt.iotstatus == IOT_STATUS_CONNECT){
ret = mqtt_data_write(payload_data,strlen(payload_data),0);
}
iot_info("payload sensor data to ali yun %s.\n",ret == 0 ? "Success" : "fail");
sleep(3);
}
mqtt移植,打开我们下载的paho.mqtt.embedded-c-master文件,里面用到的文件就那几个,MQTTPacket/src ,
这两个文件
还有两个文件
工程里iot_mqtt.c是登录文件。
void iot_mqtt_init(Cloud_MQTT_t *piot_mqtt)
{
memset(piot_mqtt, '\0', sizeof(Cloud_MQTT_t));
memcpy(piot_mqtt->sub_topic, MQTT_SUB_TOPIC,strlen(MQTT_SUB_TOPIC));
iot_info("subscribe:%s\n", piot_mqtt->sub_topic);
memcpy(piot_mqtt->pub_topic, MQTT_PUSH_TOPIC,strlen(MQTT_PUSH_TOPIC));
iot_info("pub:%s\n", piot_mqtt->pub_topic);
piot_mqtt->DataArrived_Cb = mqtt_data_rx_cb;
}
void MQTTMessageArrived_Cb(MessageData* md)
{
MQTTMessage *message = md->message;
Cloud_MQTT_t *piot_mqtt = &Iot_mqtt;
if (NULL != piot_mqtt->DataArrived_Cb) {
piot_mqtt->DataArrived_Cb((void *)message->payload, message->payloadlen);//异步消息体
}
}
int mqtt_device_connect(Cloud_MQTT_t *piot_mqtt)
{
int ret = 0;
NewNetwork(&piot_mqtt->Network);
iot_info("topic = %s\n", piot_mqtt->sub_topic);
ret = ConnectNetwork(&piot_mqtt->Network, MQTT_HOST, (int)MQTT_PORT);
if (ret != 0) {
iot_error("mqtt connect network fail \n");
ret = CONNECT_NET_ERROR;
goto error;
}
MQTTClient(&piot_mqtt->Client, &piot_mqtt->Network, 1000, piot_mqtt->mqtt_buffer, MQTT_BUF_SIZE, piot_mqtt->mqtt_read_buffer, MQTT_BUF_SIZE);
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
if (piot_mqtt->willFlag) {
data.willFlag = 1;
memcpy(&data.will, &piot_mqtt->will, sizeof(MQTTPacket_willOptions));
} else {
data.willFlag = 0;
}
data.MQTTVersion = 3;
data.clientID.cstring = MQTT_CLIENT_ID;
data.username.cstring = MQTT_USER;
data.password.cstring = MQTT_PASS;
data.keepAliveInterval = 30;
data.cleansession = 1;
ret = MQTTConnect(&piot_mqtt->Client, &data);
if (ret) {
iot_error("mqtt connect broker fail \n");
iot_error("rc = %d\n", ret);
ret = MQTT_CONNECT_ERROR;
goto error;
}
ret = MQTTSubscribe(&piot_mqtt->Client, piot_mqtt->sub_topic, opts.qos, MQTTMessageArrived_Cb);
if (ret) {
iot_error("mqtt subscribe fail \n");
ret = MQTTSUBSCRIBE_ERROR;
goto error;
}
Iot_mqtt.iotstatus = IOT_STATUS_CONNECT;
iot_info("connect %s %s\n", MQTT_HOST,ret == 0 ? "Success" : "failure");
return CONNECT_SUCCESS;
error:
return ret;
}
登录用的host port 以及用户名 密码 clinet_ID 我直接代码里写死的,这里根据上篇讲到的那个product_key device_name 还有那个DeviceSecret来生成的,网上有个工具,复制进去生成如下:
连接到服务器,可以在后台看见设备上线了。
树莓派上传数据到云端用的函数为
int mqtt_data_write(char *pbuf, int len, char retain)
{
Cloud_MQTT_t *piot_mqtt = &Iot_mqtt;
int ret = 0;
MQTTMessage message;
char my_topic[128] = {0};
strcpy(my_topic, piot_mqtt->pub_topic);
//iot_info("publish topic is :%s\r\n", my_topic);
//iot_info("mqtt tx len = %d\r\n", len);
message.payload = (void *)pbuf;
message.payloadlen = len;
message.dup = 0;
message.qos = QOS0;
if (retain) {
message.retained = 1;
} else {
message.retained = 0;
}
ret = MQTTPublish(&piot_mqtt->Client, my_topic, &message); //发布一个主题
return ret;
}
这里的topic 就是我们前一篇讲的,/sys/a1HozAJNWVx/raspberrypi/thing/event/property/post
但是上传数据要用JSON格式,所以工程里添加了CJSON库。
cJSON_AddItemToObject(root,"method",cJSON_CreateString("thing.event.property.post"));
cJSON_AddItemToObject(root,"id",cJSON_CreateString("01406633"));
cJSON_AddItemToObject(root,"params",item);
cJSON_AddItemToObject(item,"RoomTemp",cJSON_CreateNumber((float)temp/10.0));
cJSON_AddItemToObject(item,"RoomHumidity",cJSON_CreateNumber((float)himudity/10.0));
cJSON_AddItemToObject(item,"RoomLight",cJSON_CreateNumber((light_value * 10)/12));
cJSON_AddItemToObject(root,"version",cJSON_CreateString("1.0.0"));
char *payload_data = cJSON_Print(root);
iot_info("payload data = %s\n",payload_data);
这里的id随便写,app打印出来的格式为
这样云端就会收到设备端的数据了。
工程是cmake 管理的。下载后cmake CMakeLists.txt ;make命令编译,
运行sudo ./iotApp 即可。