项目流水账
新的工作要开始接触stm32,之前虽然也跟着别的项目有所接触,但是没有自己从头到尾做过一遍,现在要一个人抗下所有了,只能自学,希望能遇到所有的问题,把stm32学完。
项目需求,用移远的ec600U模组和stm32实现数据的采集和上传 只是暂时的会不断更新。
用到的模块:ec600U stm32l010f4p6 mpu6050 w25q128 lc29h暂时只有这么多
因为硬件还有没有把板子搞出来,只能暂时淘宝买各种模块去搭建一个类似的平台
给到的资源:ec600U模组 stm32l076rz mpu6050 w25q128 l76k
方案一:直接用移远的模组外挂这些sensor和flash,便宜又方便,开发量小。
方案二:stm32+移远模组 有点烦人,做的事比较多。
方案一:
第一个周末:LK76是移远的模组 可以完美的打通,也是2小时的事,但是到了mpu6050就遇到了问题,研究了移远模组的python api所谓的iic功能,调试了一整天只能读到一组不会改变的数据,尽管看了很久他的iic协议还是不行,我自信我的代码没有错。最后查了一下硬件图,发现mpu6050的模组上拉的是3.3V的电,但是移远模组上拉要求1.8V的电,应该就是这个出了问题,无奈先放弃。
第二天,加载flash模组提供了spi的接口,但是读写的时候还是出了问题,有了之前mpu6050的经验我直接去看硬件的上拉,结果一样一个是3.3V一个是1.8V.没办法剩下的时间只能看看模组提供的api学习学习。看到EC600N有挂载文件的接口,但是EC600U没有,咨询了一下移远的技术支持,他们说ram太小了放不下这个接口。提出用eeprom去存,但是考虑到数据要存的比较多,可能不够所以直接放弃方案一,白瞎了2天,只调通了一个L76K。
贴一下调成功的代码记录一下,
import net import utime from machine import UART import ure import log import utime import _thread from machine import Pin from machine import UART log.basicConfig(level=log.NOTSET) # 设置日志输出级别 log = log.getLogger("Grey") # 获取logger对象,如果不指定name则返回root对象,多次使用相同的name调用getLogger方法返回同一个logger对象 fixFlag = 0 stattus = None GNSS_Baud = 1 state = 1 readnum = 600 gpio1 = Pin(Pin.GPIO1, Pin.OUT, Pin.PULL_DISABLE, 0) if GNSS_Baud == 1: uart = UART(UART.UART1, 9600, 8, 0, 1, 0) elif GNSS_Baud == 2: uart = UART(UART.UART1, 115200, 8, 0, 1, 0) else: uart = UART(UART.UART1, 9600, 8, 0, 1, 0) def uart_read(): log.debug("uart_read start!") global state global readnum # while 1: while readnum: msgLen = uart.any() # 返回是否有可读取的数据长度 if msgLen: # 当有数据时进行读取 readnum -= 1 msg = uart.read(msgLen) utf8_msg = msg.decode() # 初始数据是字节类型(bytes),将字节类型数据进行编码 if "Usart End" in utf8_msg: break else: log.info("---------------start-----------------") log.info("uart_read msg: {}".format(utf8_msg)) log.info("---------------end-------------------") else: utime.sleep_ms(1) continue state = 0 log.debug("uart_read end!") ''' * 参数1:端口 注:EC100YCN平台与EC600SCN平台,UARTn作用如下 UART0 - DEBUG PORT UART1 – BT PORT UART2 – MAIN PORT UART3 – USB CDC PORT * 参数2:波特率 * 参数3:data bits (5~8) * 参数4:Parity (0:NONE 1:EVEN 2:ODD) * 参数5:stop bits (1~2) * 参数6:flow control (0: FC_NONE 1:FC_HW) ''' def uart_write(): log.debug("uart_write start!") count = 3 # 配置uart while count: count -= 1 utime.sleep(1) if GNSS_Baud == 1: write_msg = "$PCAS01,5*19\r\n".format(count) # 115200波特率 elif GNSS_Baud == 2: write_msg = "$PCAS01,1*1D\r\n".format(count) # 9600波特率 else: write_msg = "$PCAS01,5*19\r\n".format(count) # 115200波特率 uart.write(write_msg) # 发送数据 log.info("{}".format(write_msg)) log.debug("uart_write end!") def run(): log.debug("run start!") _thread.start_new_thread(uart_read, ()) # 创建一个线程来监听接收uart消息 _thread.start_new_thread(uart_write, ()) # 创建一个线程来监听执行uart_write函数 log.debug("run end!") class GnssGetData: # GPS数据采集及解析 def __init__(self, uartn, baudrate, databits, parity, stopbits, flowctl): if uartn == 0: UARTN = UART.UART0 elif uartn == 1: UARTN = UART.UART1 elif uartn == 2: UARTN = UART.UART2 elif uartn == 3: UARTN = UART.UART3 else: UARTN = UART.UART1 self.uart = UART(UARTN, baudrate, databits, parity, stopbits, flowctl) write_msg = "$PCAS03,1,1,1,1,1,1,1,1,0,0,,,0,0*02\r\n".format() # 115200波特率 uart.write(write_msg) utime.sleep(3) # Delay to read data stability # 读取GNSS数据并加以解析 def read_gnss_data(self): try: buf = self.uart.read(self.uart.any()) gps_data = buf.decode().strip("b") print("gps_data:",gps_data,"\n") self.r = ure.search("GNGGA(.+?)M", gps_data) print("self.r:",self.r,"\n") self.r1 = ure.search("GNRMC(.+?)M", gps_data) print("self.r1:",self.r1,"\n") self.r2 = ure.search("GPGSV(.+?)M", gps_data) print("self.r2:",self.r2,"\n") self.r3 = ure.search("GNVTG(.+?)M", gps_data) print("self.r3:",self.r3,"\n") global fixFlag if self.r1.group(0).split(",")[2] == 'A': # 有效定位 fixFlag = 1 else: fixFlag = 0 except: print("Exception:read gnss data error!!!!!!!!") raise # 获取GPS模块是否定位成功 @staticmethod def isfix(): global fixFlag return fixFlag # 获取GPS模块定位的经纬度信息 def get_location(self): if self.isfix() is 1: lat = float(self.r.group(0).split(",")[2]) // 100 + float( float(float(self.r.group(0).split(",")[2]) % 100) / 60) # lat_d = self.r.group(0).split(",")[3] # log = float(self.r.group(0).split(",")[4]) // 100 + float( float(float(self.r.group(0).split(",")[4]) % 100) / 60) # log_d = self.r.group(0).split(",")[5] # return lat, lat_d, log, log_d else: return None # 获取GPS模块授时的UTC时间 def get_utc_time(self): return self.r.group(0).split(",")[1] # 获取GPS模块定位模式 def get_location_mode(self): if self.r.group(0).split(",")[6] is '0': # print('定位不可用或者无效') return 0 if self.r.group(0).split(",")[6] is '1': # print('定位有效,定位模式:GPS、SPS 模式') return 1 if self.r.group(0).split(",")[6] is '2': # print('定位有效,定位模式: DGPS、DSPS 模式') return 2 # 获取GPS模块定位使用卫星数量 def get_used_sate_cnt(self): return self.r.group(0).split(",")[7] # 获取GPS模块定位可见卫星数量 def get_viewed_sate_cnt(self): return self.r2.group(0).split(",")[3] # 获取GPS模块定位方位角 范围:0~359。以真北为参考平面。 def get_course(self): return self.r2.group(0).split(",")[6] # 获取GPS模块对地速度(单位:KM/h) def get_speed(self): if self.r1.group(0).split(",")[7] == '': return None else: return float(self.r1.group(0).split(",")[7]) * 1.852 # 获取GPS模块定位大地高(单位:米) def get_geodetic_height(self): return self.r.group(0).split(",")[9] def showtime(): net.nitzTime() local_time = utime.localtime() stattus = '{0:0>4d}-{1:0>2d}-{2:0>2d} {3:0>2d}:{4:0>2d}:{5:0>2d}'.\ format(local_time[0], local_time[1], local_time[2], local_time[3], local_time[4], local_time[5]) print(stattus) utime.sleep(1)
下面是成功拿到的数据
gps_data: $GNGGA,083542.000,2807.70328,N,12059.06939,E,1,06,2.2,114.8,M,13.0,M,,*4B
$GNGLL,2807.70328,N,12059.06939,E,083542.000,A,A*46
$GNGSA,A,3,07,08,21,27,,,,,,,,,5.9,2.2,5.5,1*34
$GNGSA,A,3,26,35,,,,,,,,,,,5.9,2.2,5.5,4*3A
$GPGSV,2,1,05,01,34,181,,07,48,311,19,08,62,004,31,21,61,149,24,0*69
$GPGSV,2,2,05,27,34,038,32,0*58
$BDGSV,1,1,02,26,79,358,29,35,64,032,31,0*7E
$GNRMC,083542.000,A,2807.70328,N,12059.06939,E,0.00,315.13,030222,,,A,V*0F
$GNVTG,31
5.13,T,,M,0.00,N,0.00,K,A*26
$GNZDA,083542.000,03,02,2022,00,00*43
$GPTXT,01,01,01,ANTENNA OPEN*25
$GNGGA,083543.000,2807.70321,N,12059.06946,E,1,06,2.2,114.8,M,13.0,M,,*4B
$GNGLL,2807.70321,N,12059.06946,E,083543.000,A,A*46
$GNGSA,A,3,07,08,21,27,,,,,,,,,5.9,2.2,5.5,1*34
$GNGSA,A,3,26,35,,,,,,,,,,,5.9,2.2,5.5,4*3A
$GPGSV,2,1,05,01,34,181,,07,48,311,19,08,62,004,31,21,61,149,24,0*69
$GPGSV,2,2,05,27,34,038,32,0*58
$BDGSV,1,1,02,26,79,358,29,35,64,032,31,0*7E
$GNRMC,083543.000,A,28
07.70321,N,12059.06946,E,0.00,315.13,030222,,,A,V*0F
$GNVTG,315.13,T,,M,0.00,N,0.00,K,A*26
$GNZDA,083543.000,03,02,2022,00,00*42
$GPTXT,01,01,01,ANTENNA OPEN*25
$GNGGA,083544.000,2807.70314,N,12059.06954,E,1,06,2.2,114.9,M,13.0,M,,*48
$GNGLL,2807.70314,N,12059.06954,E,083544.000,A,A*44
$GNGSA,A,3,07,08,21,27,,,,,,,,,5.9,2.2,5.5,1*34
$GNGSA,A,3,26,35,,,,,,,,,,,5.9,2.2,5.5,4*3A
$GPGSV,2,1,05,01,34,181,,07,48,311
,19,08,62,004,31,21,61,149,24,0*69
$GPGSV,2,2,05,27,34,038,32,0*58
$BDGSV,1,1,02,26,79,358,29,35,64,032,31,0*7E
$GNRMC,083544.000,A,2807.70314,N,12059.06954,E,0.00,315.13,030222,,,A,V*0D
$GNVTG,315.13,T,,M,0.00,N,0.00,K,A*26
$GNZDA,083544.000,03,02,2022,00,00*45
$GPTXT,01,01,01,ANTENNA OPEN*25
$GNGGA,083545.000,2807.70311,N,12059.06960,E,1,06,2.2,114.9,M,13.0,M,,*4B
$GNGLL,2807.70311,N,12059.06960,E,083545.000,A,A*47
self.r: <match num=2>
self.r1: <match num=2>
self.r2: <m
atch num=2>
self.r3: <match num=2>
获取GPS模块是否定位成功:1(0表示失败,1表示成功)
获取GPS模块授时的UTC时间:083542.000
获取GPS模块定位模式:1(0表示定位不可用或者无效,1表示GPS、SPS 模式,2表示DGPS、DSPS 模式)
获取GPS模块定位使用卫星数量:06
获取GPS模块定位的经纬度信息:(28.12838800000001, 'N', 1
20.9844898333333, 'E')
获取GPS模块定位可见卫星数量:05
获取GPS模块定位方位角 范围:0~359。以真北为参考平面:181
获取GPS模块定位大地高:114.8米
获取GPS模块对地速度:0.0KM/h
时间线------------------------------------------------------------------------------------------------------------------2022/1/15
方案二:
第二个周末:之前没怎么做过stm32就要从头学一遍,真是苦了我。
1.首先要学习stm32cubemx去构建代码。https://www.bilibili.com/video/BV1m7411d78e?spm_id_from=333.999.0.0 这个小白教程还可以大致入门了,构建好了代码。
2.安装keil5.27 这个之前项目做过直接拿安装包装一下。但是下载pack是真的慢,https://blog.csdn.net/simon223/article/details/105090189 这个网址可以下载很多需要的包真是福音,Keil.STM32L0xx_DFP.2.2.0.pack 这个包是必下的。
3.https://blog.csdn.net/weixin_42741212/article/details/106220998 按照这个博客搞完然后编译一把,就差烧录验证了。
4.买了个正版stlink 血亏80。然后就是非常蛋疼的环节了。折磨了4个小时。
一开始这里什么都没有,然后add也找不到对应的stm32,然后安装了一个pack,Keil.STM32L0xx_DFP.2.2.0.pack 应该就是这个,然后选对device后,add才会有正确的选项。花费2小时。
然后更加坑爹的来了
st的评估板上留了一个jtag的接口,当然选择jtag去烧了简单方遍,然后就出现了上图,不管怎么调试,改驱动都无法正常使用jtag。折磨了半小时,我想起了提示的这句话在stm32 F0和L0上JTAG不可用,不知道是内部有设置还是什么的,直接放弃了jtag,用的
swd。https://blog.csdn.net/praguejing/article/details/107596701参考这个博客接好线。stlink就能搜索到接口了,直接一把入魂,小灯闪了,泪流满面。搭环境4小时,烧录验证1分钟。
5.第一个模块mpu6050.
下载了淘宝正点原子哥的xxx战舰代码。好家伙居然是标准库写的,一看我的代码是hal库的,直接没软用。就去百度淘https://blog.csdn.net/dodwind/article/details/88624941这个博客非常好,简洁明了。
https://github.com/Heimerdingerzzz/MPU6050 直接下载代码。好像都搞好了,佩服做32的资源就是多。
https://www.zhihu.com/tardis/sogou/art/191646577 这个博客是如何把DMP添加进编译 不管有没有用先添加起来。
https://blog.csdn.net/he__yuan/article/details/76559569?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.channel_param 这个博客是如何引用mpu6050.c的函数方法说了一下。暂时先把初始化先简单编译一遍。
报错了 .\test1\test1.axf: Error: L6218E: Undefined symbol hi2c1 (referred from inv_mpu.o).
原来是没有添加iic的接口
遇到小插曲 为什么在芯片引脚上设置iic会是single mapped signals 是因为后面的connectivity没有打开iic 我真是小白。
编译成功。今天就这样吧 太雷人了。明天再验。
时间线------------------------------------------------------------------------------------------------------------------2022/1/21
今天初三了,电脑修好了但是stm32的miniusb线丢了,先暂时不搞stm32,先把ec600u先研究一下。
ec600u发送数据给腾讯云,然后小程序腾讯练练接收腾讯云发送的数据。也就是mqtt的订阅和数据接收
选择腾讯云是因为之前买了个
点击新建项目
点击新建产品
点击自己新建的产品
新建自定义功能,比如当前的是板子上的aht10温湿度传感器
然后一直下一步到设备调试 新建一个设备
微信搜索小程序 腾讯连连 然后扫描上面设备的二维码
都创建好了以后去下载mqtt-fx,如下的博客https://blog.csdn.net/tiantang_1986/article/details/85101366
然后下载https://iot-exp-individual-1258344699.cos.ap-guangzhou.myqcloud.com/password%E7%94%9F
点击connect 显示绿色就表示连接成功。然后看到腾讯云上的设备也显示在线。
上报后拿到右边的调试日志
然后把这个放到mqtt-fx内
然后publish 就可以在腾讯练练的设备里看到对应的改变了,其他的功能我先不研究。
然后把当前的ec600u板子上带的aht10的数据传到腾讯小程序上。
import log import ujson import utime import _thread from machine import I2C import utime as time from TenCentYun import TXyun import checkNet from misc import Power productID = r"QOE7J6I5SH" # 产品标识 devicename = r"test" # 设备名称 devicePsk = r"spLipjbdCp62dPk+D1rH3A==" # 设备密钥(一型一密认证此参数传入 None) ProductSecret = None # 产品密钥(一机一密认证此参数传入 None) # 输入发布 Topic DEF_TOPIC_PUB = r"$thing/up/property/{}/{}".format(productID, devicename) # 输入订阅 Topic DEF_TOPIC_SUB = r"$thing/down/property/{}/{}".format(productID, devicename) CLIENT_TOKEN_STR = "7df3c076-40e1-49e4-8689-2a11df7dc1c3" PROJECT_NAME = "QuecPython_TencentYun_example" PROJECT_VERSION = "1.0.0" checknet = checkNet.CheckNetwork(PROJECT_NAME, PROJECT_VERSION) log.basicConfig(level=log.INFO) txyun_log = log.getLogger("TenCentYun") class aht10class(): i2c_dev = None i2c_addre = None # Initialization command AHT10_CALIBRATION_CMD = 0xE1 # Trigger measurement AHT10_START_MEASURMENT_CMD = 0xAC # reset AHT10_RESET_CMD = 0xBA def write_data(self, data): self.i2c_dev.write(self.i2c_addre, bytearray(0x00), 0, bytearray(data), len(data)) pass def read_data(self, length): r_data = [0x00 for i in range(length)] r_data = bytearray(r_data) self.i2c_dev.read(self.i2c_addre, bytearray(0x00), 0, r_data, length, 0) return list(r_data) def aht10_init(self, addre=0x38): self.i2c_dev = I2C(I2C.I2C1, I2C.STANDARD_MODE) # 返回 i2c 对象 self.i2c_addre = addre self.sensor_init() pass def aht10_transformation_temperature(self, data): r_data = data temperature = ((r_data[2] & 0xf) << 16) | ( r_data[3] << 8) | r_data[4] temperature = (temperature * 200.0 / (1 << 20)) - 50 I2C_log.info( "current temp is {0}°C".format( round( temperature, 1))) return temperature def aht10_transformation_humidity(self, data): r_data = data # 根据数据手册的描述来转化温度 humidity = (r_data[0] << 12) | ( r_data[1] << 4) | ((r_data[2] & 0xF0) >> 4) humidity = (humidity / (1 << 20)) * 100.0 I2C_log.info( "current humi is {0}%".format( round( humidity, 1))) return humidity def sensor_init(self): # calibration self.write_data([self.AHT10_CALIBRATION_CMD, 0x08, 0x00]) time.sleep_ms(300) # at last 300ms pass def ath10_reset(self): self.write_data([self.AHT10_RESET_CMD]) time.sleep_ms(20) # at last 20ms def Trigger_measurement(self, val): # Trigger data conversion self.write_data([self.AHT10_START_MEASURMENT_CMD, 0x33, 0x00]) time.sleep_ms(200) # at last delay 75ms # check has success r_data = self.read_data(6) # check bit7 if (r_data[0] >> 7) != 0x0: I2C_log.info("Conversion has error") else: temp = self.aht10_transformation_temperature(r_data[1:6]) humi = self.aht10_transformation_humidity(r_data[1:6]) val[0] = round(temp, 1) val[1] = round(humi, 1) def network_checknet(): while True: try: checknet.wait_network_connected(30) utime.sleep_ms(2000) txyun_log.info('network_checknet ... ...') except BaseException: txyun_log.info('network_checknet: Not Net, Resatrting...') utime.sleep_ms(200) Power.powerRestart() def sub_cb(topic, msg): # 云端消息响应回调函数 TXyun_log.info("subscribe recv:") TXyun_log.info(topic.decode(), msg.decode()) def main1(): tenxun = TXyun(productID, devicename, devicePsk, ProductSecret) # 创建连接对象 tenxun.setMqtt() tenxun.setCallback(sub_cb) tenxun.subscribe(DEF_TOPIC_SUB) tenxun.start() # i2c_obj = I2C(I2C.I2C0, I2C.STANDARD_MODE) # 返回 i2c 对象 ath_dev = aht10class() ath_dev.aht10_init() while True: val = [0, 1] ath_dev.Trigger_measurement(val) send_data = ''' {{"clientToken": "{}", "method": "report", "params": {{ "lac": 0, "cid": 0, "mnc": 0, "mcc": 0, "networkType": 1,"temp": {}, "shidu": {} }} }}'''.format(CLIENT_TOKEN_STR, val[0], val[1]) send_data = ujson.loads(send_data) s = ujson.dumps(send_data) TXyun_log.info(s) tenxun.publish(DEF_TOPIC_PUB, s) utime.sleep_ms(2000) if __name__ == "__main__": log.basicConfig(level=99) CheckNet_log = log.getLogger("CheckNet") TXyun_log = log.getLogger("TXyun_log") I2C_log = log.getLogger("AHT10") checknet = checkNet.CheckNetwork(PROJECT_NAME, PROJECT_VERSION) checknet.poweron_print_once() try: checknet.wait_network_connected(30) _thread.start_new_thread(network_checknet, ()) except BaseException: CheckNet_log.info('Not Net, Resatrting...') utime.sleep_ms(200) Power.powerRestart() txyun_log.info('txyun_log.info yepc over ') print('print yepc over ') main1()
今天就这样了 ,晚上看看如何自己搭建一个mqtt服务器。
时间线------------------------------------------------------------------------------------------------------------------2022/2/3
先加一个简单的printf打印,之前一直没加。初始化一个uart然后把这个huart1对应的加进去就好了。
#include <stdio.h>
/* USER CODE BEGIN 4 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
/* USER CODE END 4 */
时隔一个月,入职也一个月了。都做的差不多了,又临时要修改方案了,真是操蛋,之前做的也只是项目的预热,板子一出来全都不一样了,fuck。
板子还是没到,但是还是叫我提前写代码,然后板子到了再调试。
先总结一下之前的做的把。
第一版 mpu6050+ec600U+w25q128+l76k mpu6050和w25q128在stm32上,l76k在ec600u上。
第二版 mpu6050+ec600U+w25q128+l76k 把外部传感器全部接到了 stm32上,剩下ec600u和stm32通信 ,要解决l76k和stm32的工作
第三版 L26-DR+ec600U+w25q128 把外部传感器全部接到了 stm32上,剩下ec600u和stm32通信 直接给我换了个gps的芯片,然后imu的芯片也去掉了L26-DR自带imu。这个是最终的版本。终于定下来~~
这个星期前几天还在弄mpu6050的dmp的问题,搞了2天好了,结果不要了。
先记录一下这个
mpu6050 之前做的能读到7个原始数据了,说明通了,现在搞姿态处理。
有2种方法 1是姿态融合需要自己去写算法,网上案例有参考一下就好了,但是对性能有点要求需要点算力。2是dmp,一个官方提供的黑盒子把,数据原始数据就可以得到姿态,移植一下就好了。
吐槽:这里当然是想用dmp的,简单移植一下就好了,但是当时这个printf一直是坏了,mpu_dmp_init初始化的时候一直卡住了 也不知道哪里有问题,一开始是以为dmp_load_motion_driver_firmware卡在这里了百度了很多有什么说中断,什么速度设置什么的,一直搞不定,卡了一天后来printf弄好了,加了点打印再试了一下,可以dmp_load_motion_driver_firmware成功了,但是这个过程非常非常非常慢,然后卡在自检这里,因为是接的模块杜邦线各种接根本不能稳定,然后干脆直接跳过自检等正式板子到,最后可以拿到姿态数据了,千辛万苦本来高高兴兴终于搞完一个模块,结果最终板子出来说直接用L26-DR,不用imu了。我直接气炸。这2天白忙活了。
至于或者融合算法我之前也是dmp一直初始化失败也是焦虑得半夜睡不着查到的。
https://www.zhihu.com/tardis/sogou/art/228805569 这个博客有说,还挺详细挺好。最后dmp能用了就直接用dmp了。这种算法什么的对工程研究起来简直浪费时间。
更新玩之前的
现在就是重新开始第三版了 蓝受..... 只给了我2周去搞代码,说2周后机子到了就要快速搞好。这周白瞎了2天就3天的时间做w25q128.
之前因为ec600u不支持外挂w25q128,导致我后面也没有去看这个,由于L26-DR暂时没有芯片,之前也没有搞过类似gps的芯片,那个l76k也是用的现成的代码,看了下文档决定,先做简单的flash。
w25q128基于stm32的例子网上例子非常多,写的好点的也就原子哥的,不过他那个不是hal写的,想直接拿过来用也比较麻烦
还好找到了个博客写的还不错
http://www.mcublog.cn/stm32/2021_01/stm32cubemx-spi-flash-w25q128/ 这个基本实现简单的读写。
涉及到的源码github是https://github.com/nimaltd/w25qxx 用的这个大叔的代码,后面fatfs的时候还改了不少。。。。
上面的都通了以后,就是要加一个管理flash的小系统了,这个我选择了一个比较小巧的fatfs。
网上找了很多的例子,还是一头雾水不知道怎么去修改,就看了下面的几个博客,很多的博客都没有讲到位最终移植部位在哪里。起码要把w25q128的什么初始化,读写接口给移植进去把,但是具体的都没有详细讲到,但是最后还是有个比较好的让我看到了关键点 就是第一篇这个讲的比较好,能让人通俗易懂。
1.https://blog.csdn.net/redeemer_Qi/article/details/108644860
2.https://blog.csdn.net/weixin_42653531/article/details/103745344
3.https://blog.csdn.net/qq_39772670/article/details/109824810
4.https://www.cnblogs.com/cage666/p/9178326.html
最关键的就是这几个初始化读写的移植,发现上面那个w25qxx的源码和上面这篇参考的这篇博客的函数名不一样,这就麻烦了鬼知道他用的是那个源码,但是直觉应该是正点原子的,然后看了一下果然,名字一点都不差的,但是正点原子的并不是单纯的w25q128的驱动源码,里面还添加了什么gpio的配置什么的。再加上我之前用的那个代码已经调通了能简单读写了,没办法只能看正点原子的代码用当前的代码去封装读写函数。就剩最后编译了。还是个大坑。
就是去配置ffconfig.h的时候。我也不看了直接按照博客的去配置,结果出现了如下的报错
newpro\newpro.axf: Error: L6218E: Undefined symbol ff_convert (referred from ff.o).
百度了一下就说什么的都有,什么包含头文件啊参数传递错误声明函数什么的。可能也是夜深了,突然脑子一动,我先不按博客的修改试试呢,然后就出现了各种奇怪的报错,然后这个报错问题还是好解决的,最后正常的编译成功,后来我在不经意中看到了2.https://blog.csdn.net/weixin_42653531/article/details/103745344 这个文档的最后可改进的地方,可能是在自定义的头里面 有些变量会影响编译。然后我就暂时先编译过了,等下周一再去测试能不能行。
还有我看了一下L26-DR的几个文档,发现这个gps好像和别的gps返回的数据有点不一样的,如果只是和普通的gps芯片一样的化返回的也就那几个参数和数据,分析的源码我也在github参考的下了一份。千万要一样啊 ,不一样那就完犊子了。我一个人有点难受了。
后续:
1.检测一下这个存储能不能完成功能。下周一就知道了。
2.L26-DR这个芯片要在stm32上工作起来,参考的例子估计是没有了 要自己调了,先暂时拿l76k用着,但是好像这2个很多不一样,弄好了也没意义。这个感觉要被搞很久很久。
3.stm32和L26-DR的通信,用的是uart,这个简单,ec600u那边的uart收发的代码之前调试的都可以了。
4.还有就是把这个数据通过ec600u和mqtt传出去。这个暂时用腾讯云是可以的,但是目前具体要通过什么方式或者什么样的服务器还不知道,可以延后一下。
据说只有2个月的时间去实现,然后就我一个人做,咋看不多的东西,但是没有机器再加上我是个stm32的小白,之前也没做过这种项目,期间还有其他c++的东西叫我写,好苦啊~~~~
时间线------------------------------------------------------------------------------------------------------------------2022/3/5
又来更新了,板子千呼万唤始出来,终于在上周五到了,出乎意料的坑,没有usb,只有一个sw的烧录接口,其他什么都没有了,stm32的芯片还给换了 导致后面出了大毛病。
遇到的问题:
1.没有和那种开发板一样把usb引出来,很多针脚都没有引出来,还要买漆包线,焊枪去飞线。(这个也能忍了)
2.因为之前写好的ec600u的代码是在开发板上的用的是python的版本,但是现在只留了串口,只能通过at指令去配置。(之前写的代码全部白瞎了)
3.l26-dr这个芯片也没有引出串口的针脚,目前是没有验证的方法,只能飞完线,然后通过电脑的串口去试验,没做过没啥经验,只能先试,再写。
首先遇到的问题就是没有usb接出来,导致异常不习惯,芯片换了stm32l010f4,flash和sram都是比较小的,关键是sram,只有2k导致后面的fatfs移植不上去,还有稍微申请一个大一点的buf就会编译不过。这2个都是血淋淋的教训,之前没做过也没往硬件上想,相信硬件会换一个和之前一样的32芯片,结果完全不是。
我在移植fatfs的时候一直以为是自己配置出现了问题,老编译不过,最后才想到硬件,去查了一下被坑了一晚上。最后fatfs这个就先不做了,等换芯片新板子到。
由于sram很小导致,创建接收gps的buf也只能建800bytes,信息都抓不全。
2.没有了usb,只能通过at指令去发送数据给ec600u。
硬件坚持不加usb,最终还是要用at写。心想一个测试板子这不加那不加的,又没有最后定版。
大概查了一下AT指令,意思就是通过串口发送指令给芯片。解决的思路,首先用电脑串口去模拟实现mqtt的功能,然后再用代码实现。
博客参考 https://www.cnblogs.com/asnail/p/12810359.html 简单的AT指令的讲解,再加上FAE提供的文档。
暂时配置成这样。后来试了一下,只配置后面的也可以。
AT+CESQ
AT+CGATT?
AT+QMTCFG="version",0,4
AT+QMTCFG="pdpcid",0,3
AT+QMTCFG="ssl",0,0,0
AT+QMTCFG="keepalive",0,60
AT+QMTCFG="session",0,0
AT+QMTCFG="timeout",0,20,3,1
AT+QMTCFG="will",0,0
AT+QMTCFG="recv/mode",0,0
AT+QMTCFG="qmtping",0,10
AT+QMTCFG="send/mode",0,0
----------------------------------------------------------
AT+QMTOPEN=0,"101.34.201.128",1883
AT+QMTCONN=0,"6ba02edb371340278a329fde1a6ed37e"
AT+QMTSUB=0,1,"topic/pub",0
AT+QMTPUBEX=0,1,0,0,"topic/pub",10
这里卡了很久,因为在输入AT+QMTOPEN=0,"101.34.201.128",1883后要赶紧输入AT+QMTCONN=0,"6ba02edb371340278a329fde1a6ed37e" 否则会导致链路层错误,卡了我整整2小时。当连上去的那一刹那,整个人都舒服了。
电脑串口成功了,那代码就灰常简单了。
uint8_t at0[]="at\r\n";
uint8_t at1[]="AT+QMTOPEN=0,\"101.34.201.128\",1883\r\n";
uint8_t at2[]="AT+QMTCONN=0,\"6ba02edb371340278a329fde1a6ed37e\"\r\n";
uint8_t at3[]="AT+QMTSUB=0,1,\"topic/pub\",0\r\n";
uint8_t at4[]="AT+QMTPUBEX=0,1,0,0,\"topic/pub\",10\r\n";
uint8_t buf[]="yepc hello word\r\n";
HAL_UART_Transmit(&huart2, at0,sizeof(at0)-1,0xffff);
HAL_Delay(500);
HAL_UART_Transmit(&huart2, at1,sizeof(at1)-1,0xffff);
HAL_Delay(500);
HAL_UART_Transmit(&huart2, at2,sizeof(at2)-1,0xffff);
HAL_Delay(500);
HAL_UART_Transmit(&huart2, at3,sizeof(at3)-1,0xffff);
memset(at4,0,sizeof(at4));
sprintf(&at4[0],"AT+QMTPUBEX=0,1,0,0,\"topic/pub\",%d\r\n",sizeof(buf)-1);
HAL_UART_Transmit(&huart2, at4,sizeof(at4)-1,0xffff);
//printf("sizeof:%d\r\n",sizeof(at4)-1);
HAL_Delay(200);
HAL_UART_Transmit(&huart2, buf,sizeof(buf)-1,0xffff);
这样就成了 因为没有拿到具体要传的东西,现在通了,就先放着了。等具体需求下来了再完善下。
3.就剩最后一个gps模块了。
因为没有飞线我现在也没有稳定连上串口去修改配置,但是出厂是有配置的
这样我就读到了数据,大致就下面的样子
$PSTMDRSENMSG,30,3291759960,428,-1941,16468*0C
$PSTMDRSENMSG,31,3291759960,-67,158,8*06
$PSTMDRSENMSG,30,3291828170,429,-1946,16460*02
$PSTMDRSENMSG,31,3291828170,57,-76,35*06
$PSTMDRSENMSG,30,3291896364,413,-1942,16474*08
$PSTMDRSENMSG,31,3291896364,36,30,18*23
$PSTMDRSENMSG,30,3291964557,406,-1940,16464*05
$PSTMDRSENMSG,31,3291964557,-59,27,-17*29
$PSTMDRSENMSG,30,3292032772,411,-1938,16469*0D
$PSTMDRSENMSG,31,3292032772,20,-68,17*0D
$PSTMDRSENMSG,30,3292100983,423,-1955,16461*0F
$PSTMDRSENMSG,31,3292100983,-28,-95,-5*34
$PSTMDRSENMSG,30,3292169305,406,-1945,16477*05
$PSTMDRSENMSG,31,3292169305,-57,45,-14*27
$GPRMC,205125.000,V,0000.00078,S,00000.00072,E,,,060924,,,N*69
$GPGGA,205125.000,0000.00078,S,00000.00072,E,0,00,99.0,-12.93,M,0.0,M,,*6F
$GPVTG,,T,,M,,N,,K,N*2C
$GNGSA,A,1,,,,,,,,,,,,,99.0,99.0,99.0*1E
$GNGSA,A,1,,,,,,,,,,,,,99.0,99.0,99.0*1E
$GNGSA,A,1,,,,,,,,,,,,,99.0,99.0,99.0*1E
$GPGLL,0000.00078,S,00000.00072,E,205130.000,V,N*53
$PSTMANTENNASTATUS,-1,0,0,0*7D
$PSTMDRCONFID,100.16,100.16,182.3160,0.1145,0.00,0.5669,0.000602,0.050000,100.0000,100.2,100.2,-1.6,0.0*1F
$PSTMDRGPS,-0.000013071,0.000012036,0.00000,0.00000,99.000,99.000,99.000,0.000,0.000,0.00000,-12.9*42
$PSTMDRSTEP,15,1.64763,0.00173,0,0,1.000,1.000,1*2F
$PSTMDRSTYPE,3*58
$PSTMDRUPD,0.0,0.0,1.1,0.00,-1.955,0.000,-0.000002,0.000000,0.0*75
$PSTMDRSTATE,3295170100,-0.0000041,-0.0000062,-0.32,0.00,1.6483,0.7582,0.02290,-0.000002,0.000000,-12.9*61
$PSTMDRCAL,0,0,0,0,ff,1,1,N*0C
$PSTMDRAHRS,-13.0,5.8,0.0,14.000,0.425,0.0*20
$PSTMDRGNSA,0,0,0,0,0,0.00,0.00,0.00,0.00,0.00,21.00,10.00,0.10,35.00*0C
$PSTMDREPE,141.42,-1.00*72
$PSTMDRDEBUG,-1.0,2.0,0.3,0.0,0.0,0.0*70
然后查了一下资料,据说只要用到$GPGGA和$GPRMC 就可以得到定位的信息。等飞完线就把其他的都关掉,就开这2个还有PSTMDRSENMSG
然后就是分析数据,这个我在GitHub上找到了代码