Loading

NIOS和ESP8266的联用

WIFI模块

C程序

在Quartus中,打开tools-Nios II Software Bulid Tools for Eclipse,创建好项目后,在Eclipse中编写C代码:

main.c

#include <stdio.h>
#include <sys/unistd.h>
#include <io.h>
#include <string.h>
#include "system.h"
#include "altera_avalon_uart_regs.h"
#include "alt_types.h"
#include "sys/alt_irq.h"
#include "myuart.h"
#include "esp8266.h"

char ts[128];

int main(void)
{

    UART_ISR_Init();	//串口初始化
    ESP8266_Init();		//wifi模块初始化
    sprintf(ts,"AT+MQTTPUB=0,\"th180406\",\"{\\\"temperture\\\":%d.%d\\,\\\"humidity\\\":%d.%d}\",1,0\r\n",
    			29,3,14,5);
    ESP_PUB(ts);			//发布topic

    while(1)
    {
    }
    return 0;
}

myuart.c

#include "myuart.h"

unsigned char esp8266_buf[128];
unsigned short esp8266_cnt;
unsigned short esp8266_cntPre;

void UART_Irq_Handler(void)
{
	alt_u8 rx_dat;
	alt_u16 status;
  //读取接收数据
	do{
		status = IORD_ALTERA_AVALON_UART_STATUS(UART_1_BASE);
	}while(!(status & ALTERA_AVALON_UART_STATUS_RRDY_MSK));

	rx_dat = IORD_ALTERA_AVALON_UART_RXDATA(UART_1_BASE);
	if(esp8266_cnt >= sizeof(esp8266_buf))
			esp8266_cnt = 0; //防止串口被刷爆
	esp8266_buf[esp8266_cnt++]=rx_dat;
}
void UART_ISR_Init(void)
{
	//清除中断标志寄存器
  IOWR_ALTERA_AVALON_UART_STATUS(UART_0_BASE, 0x0);
  //注册中断

   alt_ic_isr_register(UART_0_IRQ_INTERRUPT_CONTROLLER_ID,
   		  UART_0_IRQ,
   		  UART_Irq_Handler,
   		  0x0,
   		  0x0);
  //允许UART接收中断
  IOWR_ALTERA_AVALON_UART_CONTROL(UART_0_BASE, 0x0080);
}

/*
 * 串口发送字符串函数
 * */
void Uart_sendString(char *data, unsigned char len)
{
	alt_u8 i;
	for(i=0;i<len;i++)
	{
		while(!(IORD_ALTERA_AVALON_UART_STATUS(UART_0_BASE)&
				  ALTERA_AVALON_UART_STATUS_TRDY_MSK));
		IOWR_ALTERA_AVALON_UART_TXDATA(UART_0_BASE, data[i]);
	}
}

esp8266.c

#include "esp8266.h"
#include "myuart.h"
#include <stdio.h>
#include <sys/unistd.h>
#include <string.h>

#define ESP8266_WIFI_INFO		"AT+CWJAP=\"WIFI名称\",\"密码\"\r\n"
#define ESP8266_MQTT_USERCFG		"AT+MQTTUSERCFG=0,1,\"ESP32\",\"espressif\",\"1234567890\",0,0,\"\"\r\n"
#define ESP8266_MQTT_CONN		"AT+MQTTCONN=0,\"服务器域名\",端口号,0\r\n"
#define ESP8266_MQTT_SUB1		"AT+MQTTSUB=0,\"主题1\",1\r\n"
#define ESP8266_MQTT_SUB2		"AT+MQTTSUB=0,\"主题2\",1\r\n"

extern unsigned char esp8266_buf[128];
extern unsigned short esp8266_cnt;
extern unsigned short esp8266_cntPre;


//==========================================================
//	函数名称:	ESP8266_Init
//
//	函数功能:	初始化ESP8266
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:
//==========================================================
void ESP8266_Init(void)
{

	//ESP8266_Clear();

	printf("1.AT+RST\n");		//向串口1输出信息
	while(ESP8266_SendCmd("AT+RST\r\n", "OK"))	//向esp8266发送指令
		usleep(500000);//delay 500ms

	printf("2. CWMODE\n");
	while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
		usleep(500000);

	printf("3. AT+CWDHCP\r\n");
	while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))
		usleep(500000);

	printf("4. CWJAP\r\n");
	while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
		usleep(500000);

	//用户信息配置
	printf("5. AT+MQTTUSERCFG\n");
	while(ESP8266_SendCmd(ESP8266_MQTT_USERCFG, "OK"))
		usleep(500000);

	//连接MQTT服务器
	printf("6. AT+MQTTCONN\n");
	while(ESP8266_SendCmd(ESP8266_MQTT_CONN, "MQTTCONNECTED"))
		usleep(500000);

	//订阅主题
	printf("7. AT+MQTTSUB1\n");
	while(ESP8266_SendCmd(ESP8266_MQTT_SUB1, "OK"))
		usleep(500000);
	//订阅主题
	printf(" AT+MQTTSUB2\n");
	while(ESP8266_SendCmd(ESP8266_MQTT_SUB2, "OK"))
		usleep(500000);

	printf("8. ESP8266 Init OK\n");

}

//==========================================================
//	函数名称:	ESP8266_WaitRecive
//
//	函数功能:	等待接收完成
//
//	入口参数:	无
//
//	返回参数:	REV_OK-接收完成		REV_WAIT-接收超时未完成
//
//	说明:		循环调用检测是否接收完成
//==========================================================
alt_u8 ESP8266_WaitRecive(void)
{

	if(esp8266_cnt == 0) 							//如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数
		return REV_WAIT;

	if(esp8266_cnt == esp8266_cntPre)				//如果上一次的值和这次相同,则说明接收完毕
	{
		esp8266_cnt = 0;							//清0接收计数

		return REV_OK;								//返回接收完成标志
	}

	esp8266_cntPre = esp8266_cnt;					//置为相同

	return REV_WAIT;								//返回接收未完成标志

}

//==========================================================
//	函数名称:	ESP8266_SendCmd
//
//	函数功能:	发送命令
//
//	入口参数:	cmd:命令
//				res:需要检查的返回指令
//
//	返回参数:	0-成功	1-失败
//
//	说明:
//==========================================================
unsigned char ESP8266_SendCmd(char *cmd, char *res)
{

	unsigned char timeOut = 200;

	Uart_sendString(cmd, strlen((const char *)cmd));	//向串口0发送数据

	while(timeOut--)
	{
		if(ESP8266_WaitRecive() == REV_OK)
		{
			if(strstr((const char *)esp8266_buf, res) != NULL)		//如果检索到关键词
			{
				ESP8266_Clear();									//清空缓存

				return 0;
			}
		}

		usleep(10000);	//delay 10ms
	}

	return 1;

}

//==========================================================
//	函数名称:	ESP8266_Clear
//
//	函数功能:	清空缓存
//
//	入口参数:	无
//
//	返回参数:	无
//
//	说明:
//==========================================================
void ESP8266_Clear(void)
{

	memset(esp8266_buf, 0, sizeof(esp8266_buf));
	esp8266_cnt = 0;

}

//主题发布
void ESP_PUB(char *cmd)
{
	while(ESP8266_SendCmd(cmd, "SUBRECV"))
		usleep(500000);
}

Verilog代码

定义了两个串口,只使用了串口0。

module uart_test(
		clk,
		rst_n,
		uart0_rx,
		uart0_tx,
		uart1_rx,
		uart1_tx
);

		input clk;
		input rst_n;
		input uart0_rx;
		output uart0_tx;
		input uart1_rx;
		output uart1_tx;
		
    
    uart_qsys u0 (
        .clk_clk            (clk),            //            clk.clk
        .reset_reset_n      (rst_n),      //          reset.reset_n
        .uart0_external_rxd (uart0_rx), // uart0_external.rxd
        .uart0_external_txd (uart0_tx), //               .txd
        .uart1_external_rxd (uart1_rx), // uart1_external.rxd
        .uart1_external_txd (uart1_tx) //               .txd
    );

endmodule

引脚定义:

连线:

esp-01s FPGA(EP4C6F17C8)
3V3 3V3
GND GND
RX M12(uart0_tx)
TX N16(uart0_rx)

测试

在Eclipse中运行程序,当ESP8266做好相关配置,则会打印出如下信息:

ESP8266连接手机热点:

在MQTTX中检测FPGA发来的数据:

如图测试成功

总结

大部分的代码是从stm32移植过来的,基本只做了串口的改动。由于FPGA上的ram资源不多,在编写代码应该尽量减少代码量。

参考:https://www.bilibili.com/video/BV15t411u7ws?p=7&vd_source=1c653b4d6d3f8ae1c834471e7fd829f0

posted @ 2023-02-23 17:07  记录学习的Lyx  阅读(31)  评论(0编辑  收藏  举报