上一篇之后鸽了大概一年多(虽然好像也没人看),但是最近无聊,发现微雪出了个给RP2040的LCD小屏幕,大概是智能手表的大小,实在是心动,但是微雪的整套板子又太贵(且没必要),于是万能的某宝搞定一块35块钱,同样是GC9A01A驱动芯片的屏幕,但是吃水不忘挖井人,还是把微雪的资料发出来,淘宝那个自己搜就好,多得很
RP2040-LCD-1.28 - Waveshare Wiki
等了两天,屏幕到货了,由于之前没拍,只能这会儿拍一个连好线的了(请忽略杂乱的桌子和已经点亮的屏幕)
之后就是下载代码了,微雪已经提供好了现成的亮屏固件,点亮其实没啥复杂的,烧写就对了
之后觉得挺没意思的,然后翻出来一块凑单用的心率血氧传感器MX30102,想着干脆搞到一起试一下,然后就开始了两个小时的折腾之路
MX30102的代码也是百度直接搜的,某家开发板的,老规矩,直接上连接
GitHub - TPYBoard/TPYBoard-v102: TPYBoard v102开发板的典型实例资料
毕竟我也是第一次在实际项目中写python,上一次看python语法好像还是2019还是2018年来着,然后看了RP2040的电路图就直接连线搞了,因为屏幕已经用了一个3V3引脚,所以就理所当然的把3V3_EN拿出来用了,结果一连线一上电,板子怎么都连不上电脑了,整个人完全傻了
后面拿出一块没焊引脚的板子发现是好的,理所当然的怀疑USB口坏了(毕竟这个板子买完焊接点了一次LED就吃灰了一年之久),于是开始了,找焊台,修焊台,焊引脚,然后重新连线的过程
结果重新连接后,新板子也不能用,我就怀疑,这个3V3_EN的引脚是不是有猫腻,果然,拔下来就好了
这就有问题了,板子只有一个3V3,但是还好,搞嵌入式的永远不会缺一个东西,就是USB转TTL,果断拿了一个出来,用它来供电
然后开始移植代码,因为我还没研究明白python的import是怎么回事(到最后其实理解了一点,不多),就全放到一个main.py里面了
然后,因为python对格式的硬要求,各种报错
接着就开始提示I2C错误,我才搞明白,弄了半天各家的micropython的硬件库是不一样的啊(原谅我,真的第一次写python)
然后就开始看两套I2C代码的对比
那个疑似ESP32板子的I2C是这样的
class MAX30102():
#默认使用引脚X1作为中断引脚,连接模块的INT引脚
#默认使用TPYBoard v102的i2c(2)接口 SCL=>Y9 SDA=>Y10
def __init__(self,i2c_id=2,address=0x57, pin='X1'):
print("intpin: {0}, address: {1}".format(pin, address))
self.i2c = I2C(i2c_id,I2C.MASTER, baudrate=400000)
self.address = address
self.interrupt =Pin(pin,Pin.IN) #设置中断引脚为输入模式
self.reset() #软复位
pyb.delay(1000)
#reg_data = self.i2c.mem_read(1, self.address, REG_INTR_STATUS_1)
addr = self.i2c.scan()
if address not in addr:
print('max30102 device not found')
elif not self.i2c.is_ready(address):
print('max30102 device not response')
else:
self.setup()
def shutdown(self):
"""
关闭模块
"""
self.i2c.mem_write(b'\x80', self.address, REG_MODE_CONFIG)
def reset(self):
"""
Reset the device, this will clear all settings,
so after running this, run setup() again.
"""
self.i2c.mem_write(b'\x40', self.address, REG_MODE_CONFIG)
def setup(self, led_mode=b'\x03'):
"""
模块的初始化设置
"""
self.i2c.mem_write(b'\xc0', self.address, REG_INTR_ENABLE_1)
self.i2c.mem_write(b'\x00', self.address, REG_INTR_ENABLE_2)
self.i2c.mem_write(b'\x00', self.address, REG_FIFO_WR_PTR)
self.i2c.mem_write(b'\x00', self.address, REG_OVF_COUNTER)
self.i2c.mem_write(b'\x00', self.address, REG_FIFO_RD_PTR)
self.i2c.mem_write(b'\x4f', self.address, REG_FIFO_CONFIG)
self.i2c.mem_write(led_mode, self.address, REG_MODE_CONFIG)
self.i2c.mem_write(b'\x27', self.address, REG_SPO2_CONFIG)
self.i2c.mem_write(b'\x24', self.address, REG_LED1_PA)
self.i2c.mem_write(b'\x24', self.address, REG_LED2_PA)
self.i2c.mem_write(b'\x7f', self.address, REG_PILOT_PA)
def set_config(self, reg, value):
self.i2c.mem_write(value, self.address, reg)
def read_fifo(self):
"""
读取寄存器的数据
"""
red_led = None
ir_led = None
#从寄存器中读取1个字节的数据
reg_INTR1 = self.i2c.mem_read(1, self.address, REG_INTR_STATUS_1)
reg_INTR2 = self.i2c.mem_read(1, self.address, REG_INTR_STATUS_2)
d = self.i2c.mem_read(6, self.address, REG_FIFO_DATA)
# mask MSB [23:18]
red_led = (d[0] << 16 | d[1] << 8 | d[2]) & 0x03FFFF
ir_led = (d[3] << 16 | d[4] << 8 | d[5]) & 0x03FFFF
return red_led, ir_led
def read_sequential(self, amount=100):
"""
读取模块上红色LED和红外光LED测量的数据
"""
red_buf = []
ir_buf = []
for i in range(amount):
while(self.interrupt.value() == 1):
#等待中断信号
pass
red, ir = self.read_fifo()
red_buf.append(red)
ir_buf.append(ir)
return red_buf, ir_buf
而RP2040的I2C库是这样的
之后就试着改了一下,想着I2C反正就是IC地址,寄存器地址这点东西
改了之后的结果是
class MAX30102():
#默认使用引脚X1作为中断引脚,连接模块的INT引脚
#默认使用TPYBoard v102的i2c(2)接口 SCL=>Y9 SDA=>Y10
def __init__(self,i2c_id=1,address=0x57, pin='X1'):
#print("intpin: {0}, address: {1}".format(pin, address))
self.i2c = I2C(i2c_id,scl=Pin(7),sda=Pin(6),freq=400_000)
self.address = address
#self.interrupt =Pin(pin,Pin.IN) #设置中断引脚为输入模式
self.reset()
time.sleep(1)#软复位
#delay(1000)
#reg_data = self.i2c.readfrom_mem(1, self.address, REG_INTR_STATUS_1)
addr = self.i2c.scan()
if address not in addr:
print('max30102 device not found')
# elif not self.i2c.is_ready(address):
# print('max30102 device not response')
else:
self.setup()
def shutdown(self):
"""
关闭模块
"""
self.i2c.writeto_mem(b'\x80', self.address, REG_MODE_CONFIG)
def reset(self):
"""
Reset the device, this will clear all settings,
so after running this, run setup() again.
"""
self.i2c.writeto_mem(self.address,REG_MODE_CONFIG,'0x40',addrsize=8)
def setup(self, led_mode=b'\x03'):
"""
模块的初始化设置
"""
self.i2c.writeto_mem(self.address, REG_INTR_ENABLE_1,b'\xc0',addrsize=8)
self.i2c.writeto_mem(self.address, REG_INTR_ENABLE_2,'0x00',addrsize=8)
self.i2c.writeto_mem(self.address, REG_FIFO_WR_PTR,'0x00',addrsize=8)
self.i2c.writeto_mem(self.address, REG_OVF_COUNTER,'0x00',addrsize=8)
self.i2c.writeto_mem(self.address, REG_FIFO_RD_PTR,'0x00',addrsize=8)
self.i2c.writeto_mem(self.address, REG_FIFO_CONFIG,'0x4f',addrsize=8)
self.i2c.writeto_mem(self.address, REG_MODE_CONFIG,led_mode,addrsize=8)
self.i2c.writeto_mem(self.address, REG_SPO2_CONFIG,'0x27',addrsize=8)
self.i2c.writeto_mem(self.address, REG_LED1_PA,'0x24',addrsize=8)
self.i2c.writeto_mem(self.address, REG_LED2_PA,'0x24',addrsize=8)
self.i2c.writeto_mem(self.address, REG_PILOT_PA,'0x7f',addrsize=8)
def set_config(self, reg, value):
self.i2c.writeto_mem(value, self.address, reg)
def read_fifo(self):
"""
读取寄存器的数据
"""
red_led = None
ir_led = None
#从寄存器中读取1个字节的数据
reg_INTR1 = self.i2c.readfrom_mem(self.address, REG_INTR_STATUS_1,1,addrsize=8)
reg_INTR2 = self.i2c.readfrom_mem(self.address, REG_INTR_STATUS_2,1,addrsize=8)
d = self.i2c.readfrom_mem(self.address, REG_FIFO_DATA,6,addrsize=8)
# mask MSB [23:18]
red_led = (d[0] << 16 | d[1] << 8 | d[2]) & 0x03FFFF
ir_led = (d[3] << 16 | d[4] << 8 | d[5]) & 0x03FFFF
return red_led, ir_led
def read_sequential(self, amount=100):
"""
读取模块上红色LED和红外光LED测量的数据
"""
red_buf = []
ir_buf = []
for i in range(amount):
# while(self.interrupt.value() == 1):
# #等待中断信号
# pass
red, ir = self.read_fifo()
red_buf.append(red)
ir_buf.append(ir)
return red_buf, ir_buf
中间试了很多次,到这块终于算成功了
然后最后就是main函数了
if __name__=='__main__':
LCD = LCD_1inch28()
LCD.set_bl_pwm(65535)
# qmi8658=QMI8658()
Vbat= ADC(Pin(Vbat_Pin))
m = MAX30102()
while(True):
#read QMI8658
# xyz=qmi8658.Read_XYZ()
red, ir = m.read_sequential(1000)
#进行分析
ir_avg = []
red_avg = []
for i in range(37):
d = calc_hr_and_spo2(ir[25*i:25*i+100], red[25*i:25*i+100])
#print(d)
if d[1]:
ir_avg.append(d[0])
if d[3]:
red_avg.append(d[2])
ir_D = (sum(ir_avg) - max(ir_avg) - min(ir_avg)) // len(ir_avg)
#red_D = (sum(red_avg) - max(red_avg) - min(red_avg)) // len(red_avg)
LCD.fill(LCD.white)
LCD.fill_rect(0,0,240,40,LCD.red)
LCD.text("RP2040-LCD-1.28",60,25,LCD.white)
LCD.fill_rect(0,40,240,40,LCD.blue)
LCD.text("micropython",80,57,LCD.white)
LCD.fill_rect(0,80,120,120,0x1805)
LCD.text("heart is:%d"%(ir_D/2),20,100-3,LCD.white)
LCD.text("times/min",20,140-3,LCD.white)
# LCD.text("ACC_Z={:+.2f}".format(xyz[2]),20,180-3,LCD.white)
LCD.fill_rect(120,80,120,120,0xF073)
# LCD.text("GYR_X={:+3.2f}".format(xyz[3]),125,100-3,LCD.white)
# LCD.text("GYR_Y={:+3.2f}".format(xyz[4]),125,140-3,LCD.white)
# LCD.text("GYR_Z={:+3.2f}".format(xyz[5]),125,180-3,LCD.white)
LCD.fill_rect(0,200,240,40,0x180f)
reading = Vbat.read_u16()*3.3/65535*2
LCD.text("Vbat={:.2f}".format(reading),80,215,LCD.white)
LCD.show()
time.sleep(0.1)
成功可以输出心率数据了,就是觉得挺不对的,应该是传感器的具体配置还是哪没弄好,改天继续弄弄吧
完整代码先不传了,改天整好了再说
LCD+MX30102