stm32 arduino 读取sd卡并在lcd(jlx12864)上播放badapple

前言

要问什么是测试单片机控制单色屏幕的最佳办法,我想badapple应该当之无愧,经典程度如helloworld。
这次,我用stm32f103c8t6+arduino框架读取sd卡,并控制jlx12864g-086液晶屏(3.3v版本)播放20fps(理论上)badapple动画。sd(tf)卡模块就是arduino上常用的那种,上面有卡槽和电平转换ic,将arduino常用的5v转成3.3v。液晶屏在某宝有,用u8g2库控制,可以看我以前的博客。
经过测试,发现该cog lcd实际帧率并不高,相较于oled,是肉眼可见的慢。和b站上的5110屏幕相比也慢。目前暂未能有效提升动画流畅度,也不知道是卡在sd的io上(可能性最大)还是lcd上还是别的什么地方,读者有兴趣可以在本文基础上进一步研究。
注意,本文需要结合其他的badapple实现文章进行阅读。本文代码皆为在他人基础上加以改动。在此表达感谢。

引脚连接

SD模块(硬SPI控制)单片机引脚
VCC5V
GNDGND
MISOPA6
MOSIPA7
SCKPA5
CSPA4
12864(软SPI控制)单片机引脚
CSPA3
RSTPA2
RSPA1
SDAPA0
SCLKPC15
VDD3.3V
VSSGND

代码示例

badapple.ino

#include <SD.h>
#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#define LCD_WIDTH 128
#define LCD_HEIGHT 64
//注意是count,乘以8=80,才是真实width
#define WIDTH_COUNT 10
#define HEIGHT 60
#define SIZE (WIDTH_COUNT*HEIGHT)
#define top (LCD_HEIGHT - HEIGHT) / 2
#define left (LCD_WIDTH - WIDTH_COUNT * 8) / 2
//液晶屏驱动
U8G2_UC1701_MINI12864_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ PC15, /* data=*/ PA0, /* cs=*/ PA3, /* dc=*/ PA1, /* reset=*/ PA2);
int sdCSPin=PA4;
char buf[SIZE];
File root;
File myFile;

void draw() {
  u8g2.drawBitmap(left, top, WIDTH_COUNT, HEIGHT, (const uint8_t*)buf);
}

void setup(){
  Serial.begin(9600);
  u8g2.begin();
  if (!SD.begin(sdCSPin)) {
    Serial.println("Initialization Failed");
    return;
  }
  Serial.println("Initialization OK");
  myFile = SD.open("BADAPP~2.BIN");
}

void loop(){
  u8g2.firstPage();
  do {
    draw();
  } while(u8g2.nextPage());

  if  (myFile && myFile.available()) {
    myFile.read(buf, SIZE);
  } else {
    myFile.close();
    myFile = SD.open("BADAPP~2.BIN");
    Serial.println("Replay.");
    delay(5000);
  }
}

下面是将视频转为图像数据的matlab代码。在安装matlab时需要装图像处理工具箱这个组件,否则报错。不想安装matlab的读者可以自己写。

%% Bad Apple 图像数据生成程序
% 需事先将视频文件放在代码所在文件夹内
% 本例最终生成图像尺寸为80*60,可按需修改
%该源码来源于网络,具体作者未知,棉花糖做了细微修改
%如果侵犯了你的权益,我会及时删除
%% 预处理
clc;clear;
fileName = 'badapple.mp4';              	% 文件名可按实际修改
video = VideoReader(fileName);              % matlab自带,读取视频文件
numOfFrames = video.Duration * video.frameRate;	% 总帧数 = 总时长 * 帧率 
guiWaitBar = waitbar(0,'Please wait');  	% 新建进度条GUI
fid = fopen('badapple_20FPS.bin','a');    	% 新建二进制文件,以添加方式打开
%% 图像处理
tic;                                            % 计时开始
k = 1;
while hasFrame(video)                       	% 只要视频还没读取完就循环
    frame = readFrame(video);               	% 每执行一次readframe,帧数减少1
    if rem(k,2)==0                          	% 每隔3帧处理一帧,即原视频30FPS,此处取15FPS
        D = im2bw(frame,0.5);               	% 对图像二值化,0.5代表阈值取中值
        rawData = imresize(D,[60 80]);      	% 保持原比例调整尺寸到80*60
        %fwrite(fid,imageData','ubit1','ieee-be'); % 按位,以大端模式写入二进制文件
        fwrite(fid,rawData','ubit1','ieee-be');
    end
    k = k+1;
    waitbar(k/numOfFrames,guiWaitBar);          % 设置进度条当前值
end
close(guiWaitBar);                              % 关闭进度条
fclose(fid);
toc;                                            % 计时停止

问题排查

1. sd卡无法读取

这个问题非常复杂,可能的原因有很多。
如果用的是stlink或jlink,那么请换成usb-ttl串口下载工具。我在测试时发现stlink调试sd卡是一直失败的,card.init通过,但卡在volume.init。换了usb-ttl可以正常使用。原因未可知,如果有知道原因的大佬麻烦解答一下。
先烧一个串口输出例程看看是否正常,检查波特率对不对。
运行cardinfo(官方例程)。官方例程是用硬件SPI1引脚。默认CS引脚是4,其实就是stm32f103上的PA4。也就是说只需要切换板型即可。引脚按照上文表格连接,保持不变。接下来看串口输出,是否能正常初始化、读取卡型、获取文件名等。
如果能成功获取文件名,那么要注意读取出的文件名是否是badapp~1.bin这种。如果是,请尝试把该名称替换掉代码里的文件名,再进行测试。
如果不能成功获取到文件名,那么有以下方法:

  1. 用avr版的arduino(比如uno)测试模块及sd卡是否正常
  2. 换更短的杜邦线
  3. 降低SPI速度。比如cardinfo例程中,有if (!card.init(SPI_HALF_SPEED, chipSelect)) 这一句,可以把
    SPI_HALF_SPEED换成SPI_QUARTER_SPEED,或者除以1个值再进行测试。这里补充一下,如果读者遇到stm32+arduino i2c无法正常工作,也可以降低速度。

如果sd卡信息能够成功读取,那么恭喜你节省了99%的精力,并距离成功仅一步之遥(确信)。

2. lcd无显示

可以用我之前发的代码测试一下是否可以正常输出。
检查引脚是否正确、排针是否虚焊。如果买了多个屏幕那么换一个看看。

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要将GPS模块信息发送到LCD12864,您需要使用以下步骤: 1. 首先,您需要连接GPS模块和LCD12864到Arduino板上。确保它们都连接到正确的引脚。 2. 接下来,您需要编写一个程序来读取GPS模块信息。您可以使用现成的GPS库来处理这个任务。其中一个常用的库是Adafruit_GPS。 3. 使用该库,您可以轻松读取GPS模块的数据。只需调用适当的函数即可获取经度、纬度、速度等信息。 4. 接下来,您需要将这些信息发送到LCD12864。您可以使用LCD12864库来显示文本和图形。您可以在代码中使用print命令来将GPS信息显示在LCD屏幕上。 5. 最后,您需要将程序上传到Arduino板上,然后观察LCD屏幕是否正确显示GPS信息。 下面是一个简单的示例程序,可帮助您完成此操作: ``` #include <Adafruit_GPS.h> #include <SoftwareSerial.h> #include <LiquidCrystal.h> #define RXPin 3 #define TXPin 4 #define LCD_RS 7 #define LCD_E 8 #define LCD_D4 9 #define LCD_D5 10 #define LCD_D6 11 #define LCD_D7 12 SoftwareSerial mySerial(RXPin, TXPin); Adafruit_GPS GPS(&mySerial); LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7); void setup() { GPS.begin(9600); GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); GPS.sendCommand(PGCMD_ANTENNA); lcd.begin(16, 2); } void loop() { if (GPS.newNMEAreceived()) { GPS.parse(GPS.lastNMEA()); } lcd.clear(); lcd.setCursor(0, 0); lcd.print("Lat: "); lcd.print(GPS.latitude, 4); lcd.print(" Long: "); lcd.print(GPS.longitude, 4); delay(1000); } ``` 这个程序将GPS模块的经度和纬度信息显示在LCD屏幕上。您可以根据需要进行修改以适应特定的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值