移植MQTT客户端项目Day4

一.回顾总结

昨天作者已经写好了环形缓冲区的代码,经测试无误。但是作者最后也说,读取USART1的数据一定不能死等待,为了解决这个问题我们先思考一下WIFI模块层面的代码怎么设计。WIFI模块层面实际就是发送AT指令和接收返回指令的程序,这里会有两个函数(任务):

int ATSendCmd(char *buf, int len, char *resp, int resp_len, int timeout);

void ATRecvParser( void * params);

ATSendCmd负责发送AT指令并读取返回状态,对于MCU来说,串口发送完数据然后等待ESP-12F返回是一个很漫长的过程,为了有效利用MCU,我们需要让其阻塞,不要占用处理器。因此,在ATSendCmd发送完AT指令后就上锁(通过FreeRTOS的信号量实现)阻塞,等待ATRecvParser解析完毕返回后将其唤醒

二.编写WIFI模块的程序

int8_t ATSendCmd(uint8_t* buf, int len, int timeout)
{
	int8_t ret;
	int8_t err;
	
	hal_at_send(buf, len);
	hal_at_send("\r\n", 2);
	
	/* 发送完AT命令就要等待WIFI模块的返回值,但这里一定不能死等待,要使用互斥锁 */
	/* 1--成功获得锁;0--失败*/
	ret = platform_mutex_lock_timeout(&at_ret_mutex, timeout);
	if (ret)
	{
		err = getATState();
		if (err == AT_OK)
		{
			return AT_OK;
		}
		else if (err == AT_ERROR)
		{
			return AT_ERROR;
		}
		else
		{
			return AT_TIMEOUT;
		}
	}
	
	return AT_TIMEOUT;
}

void ATRecvParser(void* params) // void (*ptr) (void* p) 函数类型
{
	uint8_t buf[AT_RESP_LEN];
	int index = 0;
	
	while (1)
	{
		if (index < AT_RESP_LEN) //USART1读不到数据就阻塞,不会空转
		{
			hal_at_recv(buf + index, (int)portMAX_DELAY);
		}
		
		/* 只有读到了换行才去解析数据 */
		if (index && buf[index] == '\n' && buf[index - 1] == '\r')
		{
			buf[index + 1] = '\0'; //先给出结束字符方便使用string.h库函数
			
			if (strstr("OK", buf)) //case1,接收到OK
			{
				setATState(AT_OK);
				platform_mutex_unlock(&at_ret_mutex); //成功接收到数据就解锁
				memcpy(g_at_resp, buf, index + 1); /* len?*/
			}
			else if (strstr("ERROR", buf)) //case2,接收到ERROR
			{
				setATState(AT_ERROR);
				platform_mutex_unlock(&at_ret_mutex);
			}
			else if (isSpecialAT(buf)) //case3,接收到特殊字符串
			{
				procSpecialAT(buf);
			}
		}
		
		index ++; //只要读到了数据,写指针index都++		
	}
}

 以下为改进后的usart_read函数和中断函数

void myUSART1_Read(uint8_t* c, int timeout)
{
	while (1)
	{
		if (ring_buffer_read(c, &USART1_buffer) == 0)
		{
			return;
		}
		else 
		{
			platform_mutex_lock_timeout(&USART1_Rcev_Mutex, timeout);
		}
	}
}

/* 使用环形缓冲区的中断函数 */
void USART1_IRQHandler(void)
{
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		RxData  = USART_ReceiveData(USART1);
		ring_buffer_write(RxData, &USART1_buffer);
		platform_mutex_unlock(&USART1_Rcev_Mutex); /*<!中断函数内部解锁?*/
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

因为该程序作者还没有调试,而且对AT返回值的解析肯定还不完善,因此子函数暂不展示。

三.模拟接受AT返回值的过程

ATSendCmd函数发送完AT指令后就阻塞了,一段时间后串口接收到数据,中断函数将数据写入环形缓冲区后唤醒myUSART1_Read,同时也唤醒了 ATRecvParser。ATRecvParser将数据保存到局部数组buf中,当读到"\r\n"时就开始解析,假如接收到"OK",那么解析后就设置ATState为OK,并且唤醒ATSendCmd。ATSendCmd读取ATState并返回状态值表示OK, ERROR, TIMEOUT,至此ATSendCmd的任务就完成了。

但是今天写的程序肯定有一些问题,比如能否在中断函数中解锁unlock?对特殊AT返回值的解析肯定不完善,对于这些问题作者明天努力解决@.@

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值