[python] BPI-CanMV-K230D-Zero的电子时钟与片温检测实现

[复制链接]
 楼主| jinglixixi 发表于 2025-6-29 00:21 | 显示全部楼层 |阅读模式
#申请原创#  
@21小跑堂

Banana Pi BPI-CanMV-K230D-Zero开发板是嘉楠科技推出的一款产品,它采用K230D RISC-V芯片设计,该芯片拥有双核玄铁 C908 RISC-V CPU,内置了128MB LPDDR4 内存,提供了高性能的本地推理运算支持。
该产品具有丰富的开发资源且尺寸小巧,它适于进行边缘 AI 音视频产品的创新设计。
该产品是一套组件,除开发板外还配置了一个摄像头,以便进行图像识别处理等,详见图1所示。
9186db326361a438059e19340293a476
图1 套件组成

该开发板是采用双面器件布局,其背面如图2所示,可见其器件密度之高。
753ecf73f04dbb6faf0202542ddac1e7
图2 开发板背面

由于该开发板并没有配置相应的显示器件,为进行显示需要自行配置显示器件。
为了与其小巧的身材相配,就选取了一款I2C接口的0.96寸单色OLED屏与之相配。
要驱动显示屏,有2种方式,一种是采用模拟的方式来驱动,另一种则通过硬件的方式来驱动。
易于厂家在例程方面提供了一个基本的驱动框架,为此就利用所提供的驱动框架来实现其显示功能。
例程所提供的驱动程序框架为:
  1. from machine import FPIOA, I2C
  2. # use hardware i2c
  3. if HARD_I2C:
  4. fpioa = FPIOA()
  5. fpioa.set_function(11, FPIOA.IIC2_SCL)
  6. fpioa.set_function(12, FPIOA.IIC2_SDA)
  7. i2c=I2C(2, freq = 400 * 1000)
  8. print(i2c.scan())
  9. else:
  10. # use soft i2c
  11. i2c=I2C(5, scl = 11, sda = 12, freq = 400 * 1000)
  12. print(i2c.scan())
  13. # SSD1306 I2C address (common values: 0x3C or 0x3D)
  14. OLED_I2C_ADDR = 0x3C
  15. # Function to send a command to the SSD1306
  16. def send_command(command):
  17. # 0x00 indicates we're sending a command (as opposed to data)
  18. i2c.writeto(OLED_I2C_ADDR, bytearray([0x00, command]))
  19. # Function to send data (for pixel values) to the SSD1306
  20. def send_data(data):
  21. # 0x40 indicates we're sending data (as opposed to a command)
  22. i2c.writeto(OLED_I2C_ADDR, bytearray([0x40] + data))
  23. def send_data1(data):
  24. # 0x00 indicates we're sending data (as opposed to a command)
  25. i2c.writeto(OLED_I2C_ADDR, bytearray([0x40, data]))
  26. # SSD1306 Initialization sequence (based on datasheet)
  27. def oled_init():
  28. send_command(0xAE) # Display OFF
  29. send_command(0xA8) # Set MUX Ratio
  30. send_command(0x3F) # 64MUX
  31. send_command(0xD3) # Set display offset
  32. send_command(0x00) # Offset = 0
  33. send_command(0x40) # Set display start line to 0
  34. send_command(0xA1) # Set segment re-map (A1 for reverse, A0 for normal)
  35. send_command(0xC8) # Set COM output scan direction (C8 for reverse, C0 for normal)
  36. send_command(0xDA) # Set COM pins hardware configuration
  37. send_command(0x12) # Alternative COM pin config, disable left/right remap
  38. send_command(0x81) # Set contrast control
  39. send_command(0x7F) # Max contrast
  40. send_command(0xA4) # Entire display ON, resume to RAM content display
  41. send_command(0xA6) # Set Normal display (A6 for normal, A7 for inverse)
  42. send_command(0xD5) # Set oscillator frequency
  43. send_command(0x80) # Frequency
  44. send_command(0x8D) # Enable charge pump regulator
  45. send_command(0x14) # Enable charge pump
  46. send_command(0xAF) # Display ON
  47. # Function to clear the display (turn off all pixels)

由程序可以得知,显示屏的引脚连接关系为:
SCL-------GPIO11
SDA------GPIO12

经程序运行,其测试效果如图3所示,说明它对显示屏的驱动有效。
d9e29e37dd83c800cd87f8d9a17f1e74
图3 驱动测试

为在此基础上实现数据的显示功能,需为其配置字库及相应的显示函数。
其中字库的存储结构为:
F8X16=[
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,#0
  0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,#! 1
  0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,#" 2
  ...  ...
}

由于这里采用的编程语言是Python,因此在程序设计时还会与C语言存在一定的差别,有些功能的实现甚至需要绕行来解决。
为进行显示位置的定位,所配置的函数为:
  1. def OLED_Set_Pos(x, y):
  2. send_command(0xb0+y)
  3. send_command(((x&0xf0)>>4)|0x10)
  4. send_command(x&0x0f)

依托于该函数的支持,实现数字符号显示的函数为:
  1. def OLED_ShowCharm(x,y,chr):
  2. c=chr
  3. OLED_Set_Pos(x,y)
  4. i=0
  5. for i in range(8):
  6. u=F8X16[c*16+i]
  7. send_data([u]*1)
  8. OLED_Set_Pos(x,y+1)
  9. i=0
  10. for i in range(8):
  11. u=F8X16[c*16+i+8]
  12. send_data([u]*1)

为在数据显示过程中,能逐个数位的提取其数值,所配置的函数为:
  1. def oled_pow( m,n):
  2. result=1
  3. while (n>0) :
  4. n=n-1
  5. result*=m
  6. return result

依托前面2个函数的支持,实现数值的函数为:
  1. def OLED_ShowNum(x,y,num,len):
  2. enshow=0
  3. for t in range(len):
  4. temp=(num/oled_pow(10,len-t-1))%10
  5. if (enshow==0 & t<(len-1)):
  6. if(temp>0):
  7. enshow=1
  8. OLED_ShowCharm(x+8*t,y,int(temp)+16)

至此,就可以在OLED屏上来实现数据信息了。
为使用RTC来实现电子时钟功能,需导入RTC和time,并对RTC进行实例化,其对应的程序为:
  1. import time
  2. from machine import RTC
  3. # 实例化RTC
  4. rtc = RTC()
  5. # 获取当前时间
  6. print(rtc.datetime())
  7. # 设置当前时间
  8. rtc.init((2025,6,28,2,23,59,0,0))

这样就有了实现电子时钟功能的基础,由于 RTC的计时值是以组元的方式来管理数据的,因此读取当前时间后,所显示内容的显示为:
(2025,6,28,2,23,59,0,0)

而这样的显示数据是无法直接拿来实现的,为此需要以如下的方式来提取时间值并予以显示:
z=rtc.datetime()
OLED_ShowNum(0,2,z[4],2)
OLED_ShowNum(24,2,z[5],2)
OLED_ShowNum(48,2,z[6],2)

至此,提供添加下面的循环处理就可为此电子时钟的计时功能:
  1. # Initialize the OLED display
  2. oled_init()
  3. oled_clear()
  4. OLED_ShowChar(16, 2, 26)
  5. OLED_ShowChar(40, 2, 26)
  6. while 1:
  7. z=rtc.datetime()
  8. OLED_ShowNum(0,2,z[4],2)
  9. OLED_ShowNum(24,2,z[5],2)
  10. OLED_ShowNum(48,2,z[6],2)
  11. time.sleep(1)

经程序的运行,其显示效果如图4和图5所示。
9360b1160c41e2a8259a6ae6a886ae88
图4 整体显示效果

fd5bf5c6eecf3cca3542ddc1f4e9b096
图5 详细显示效果

此外,在 os和machine的情况下,还可以对片内温度进行检测,实现电子时钟与片温显示的主程序为:
  1. import os
  2. import machine
  3. # Initialize the OLED display
  4. oled_init()
  5. oled_clear()
  6. OLED_ShowChar(16, 2, 26)
  7. OLED_ShowChar(40, 2, 26)
  8. OLED_ShowChar(8, 4, 52)
  9. OLED_ShowChar(16, 4, 29)
  10. while True:
  11. os.exitpoint()
  12. z=rtc.datetime()
  13. OLED_ShowNum(0,2,z[4],2)
  14. OLED_ShowNum(24,2,z[5],2)
  15. OLED_ShowNum(48,2,z[6],2)
  16. temp = machine.temperature()
  17. OLED_ShowNum(24,4,temp,2)
  18. time.sleep_ms(500)

其执行后,其显示效果如图6所示。
318da53ce4966a34884ed56192b572ce
图6 显示效果

为便于字符串的显示,所配置的显示函数为:
  1. def OLED_ShowString(x,y,chr):
  2. array1=bytearray(chr, 'utf-8')
  3. for value in array1:
  4. OLED_ShowChar(x,y,value-32)
  5. x+=8

由于系统配置的Python,没有提供获取字符内码的函数,为此是借助bytearray的特点解决了这个问题。
在添加字符串显示功能后,其程序主程序为:
  1. # Initialize the OLED display
  2. oled_init()
  3. oled_clear()
  4. OLED_ShowChar(26, 3, 26)
  5. OLED_ShowChar(50, 3, 26)
  6. OLED_ShowChar(8, 5, 52)
  7. OLED_ShowChar(16, 5, 29)
  8. OLED_ShowString(5,0,"BPI-CanMV-K230D")
  9. while True:
  10. os.exitpoint()
  11. z=rtc.datetime()
  12. OLED_ShowNum(10,3,z[4],2)
  13. OLED_ShowNum(34,3,z[5],2)
  14. OLED_ShowNum(58,3,z[6],2)
  15. temp = machine.temperature()
  16. OLED_ShowNum(24,5,temp,2)
  17. #print(f"Temp: {temp}")
  18. time.sleep_ms(500)

经测试,其显示效果图7和图8所示,说明设计符号预期要求。
5be0d5cc795d5965ccea132759586df7
图7 整体显示效果

e9d24dc80679caf0bcd72f401b3ac611
图8 显示效果

演示视频:



您需要登录后才可以回帖 登录 | 注册

本版积分规则

518

主题

2934

帖子

39

粉丝
快速回复 在线客服 返回列表 返回顶部