昨天移植好了FreeRTOS和MQTT客户端代码,并解决了所有的编译和连接报错。今天开始写代码,写代码之前,首先要知道这个项目的功能需求和软件架构。
一.功能需求及软件架构
1.硬件层·:PC通过串口和MCU通信(PC没有串口,要使用USB转TTL芯片做一次转换),MCU通过串口和WIFI模块通信,我使用的是安信可公司的ESP-12F开发板。MCU作为MQTT客户端需要执行connect,subscribe,publish,disconnect操作时,需要通过网络连接服务器,并发送相应的信息。这里我们使用WIFI模块和MCU相连,MCU发送AT指令给WIFI模块,WIFI模块里面集成了一块32位处理器芯片,接收到AT指令后会根据已经烧录进去的程序执行相应的操作,去连接/断开路由器热点。
2.软件层:介绍完硬件层的设计,软件层的架构就清晰多了。
Ⅰ APP: connect ,subscibe, publish, disconnect
Ⅱ WIFI: executive AT instruction & response
Ⅲ Hardware Abstraction Layer:send & receive
Ⅳ Hardware Driver Layer: USART_Write & USART_Read
我将程序分为四层,APP层主要是执行MQTTClient的代码;WIFI层则是发送及接收AT指令;硬件层分为两层,Hardware Driver Layer提供串口的读写函数用来具体完成发送及接收AT指令的任务;而Hardware Abstraction Layer的存在只是提供一个抽象的接口,这样做的目的是降低代码耦合性,假如我们要移植这份代码到另一个MCU,而这个MCU串口引脚被占用了,我们只需要新增例如I2C的驱动代码并修改抽象层的函数即可,这样就避免了发送接收AT指令和某一个具体的硬件绑死了。
二.编写USART驱动程序
1. 我们需要实现 void myUSART1_Init(void); void myUSART1_Write(uint8_t Byte); uint8_t myUSART1_Read(void); 以及相应的myUSART3的6个函数。USART1和PC通信,USART3和WIFI模块通信。示例代码:
void myUSART1_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = BuadRate1;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 7;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
}
2.初始化步骤为:①打开GPIO和USART时钟;②配置GPIO;③配置USART结构体;④使能USART1的RXNEIE位,开启RXNE中断;⑤配置NVIC
3.现在的问题是:发送数据采用死等待的方式,接收数据采用中断的方式。但是假设有两个线程,发送AT指令和解析AT指令,中断函数必须要通知解析AT指令线程才能让其工作,这里涉及到线程的互斥和同步,作者现在没有想清楚,今天就到此为止吧@.@