使用 beaglebone Black SPI 在 DIP203-6 LCD 屏幕上显示字符
Posted
技术标签:
【中文标题】使用 beaglebone Black SPI 在 DIP203-6 LCD 屏幕上显示字符【英文标题】:Displaying the character on DIP203-6 LCD screen using beaglebone Black SPI 【发布时间】:2019-03-31 17:42:42 【问题描述】:我正在尝试使用 beagle bone black SPI 向我的 DIP203-6 LCD 写入一个字符。当光标在正确的位置闪烁时,我已经初始化了 LCD 屏幕。我面临的问题是在the data sheet 中写入字符,字符的写入需要 10 位,但 spi 只能占用 8 位。 LCD 的 RS 需要根据数据表中的命令设置为 1。我倾向于得到一些垃圾值。
在 int main() 部分,最后你可以看到我正在使用 main 上方的传输函数传输命令
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static void transfer(int fd, uint16_t* tx, uint8_t cs);
void init_display(int fd);
static void pabort(const char *s)
perror(s);
abort();
static const char *device = "/dev/spidev2.1";
static uint8_t mode=3;
static uint8_t bits = 8;
static uint32_t speed = 40000;
static uint16_t delay;
//initialization of display
void init_display(int fd)
int ret;
uint16_t tx[] =
0x0F8, 0x000, 0x0C0,
0x0F8, 0x060, 0x000,
0x0F8, 0x060, 0x0C0,
0x0FC, 0x090, 0x000,
0x0FC, 0x000, 0x020,
0x0FE, 0x000, 0x000,
0x0F8, 0x000, 0x0C0,
0x0F8, 0x0F0, 0x000,
0x0F8, 0x080, 0x000,
;
for (ret=0; ret<27; ret++)
transfer(fd,&tx[ret], 0);
usleep(2000);
static void transfer(int fd, uint16_t* tx, uint8_t cs)
int ret;
uint16_t rx[ARRAY_SIZE(tx)] = 0, ;
struct spi_ioc_transfer tr =
.tx_buf = (unsigned long)tx,
.rx_buf = 0,
.len = 1,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
.cs_change=cs,
;
printf("%u", cs);
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
// for (ret = 0; ret < ARRAY_SIZE(tx); ret++)
// if (!(ret % 6))
puts("");
// printf("%.2X ", rx[ret]);
// puts("");
static void print_usage(const char *prog)
printf("Usage: %s [-DsbdlHOLC3]\n", prog);
puts(" -D --device device to use (default /dev/spidev1.1)\n"
" -s --speed max speed (Hz)\n"
" -d --delay delay (usec)\n"
" -b --bpw bits per word \n"
" -l --loop loopback\n"
" -H --cpha clock phase\n"
" -O --cpol clock polarity\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
" -3 --3wire SI/SO signals shared\n");
exit(1);
static void parse_opts(int argc, char *argv[])
while (1)
static const struct option lopts[] =
"device", 1, 0, 'D' ,
"speed", 1, 0, 's' ,
"delay", 1, 0, 'd' ,
"bpw", 1, 0, 'b' ,
"loop", 0, 0, 'l' ,
"cpha", 0, 0, 'H' ,
"cpol", 0, 0, 'O' ,
"lsb", 0, 0, 'L' ,
"cs-high", 0, 0, 'C' ,
"3wire", 0, 0, '3' ,
"no-cs", 0, 0, 'N' ,
"ready", 0, 0, 'R' ,
NULL, 0, 0, 0 ,
;
int c;
c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts,
NULL);
if (c == -1)
break;
switch (c)
case 'D':
device = optarg;
break;
case 's':
speed = atoi(optarg);
break;
case 'd':
delay = atoi(optarg);
break;
case 'b':
bits = atoi(optarg);
break;
case 'l':
mode |= SPI_LOOP;
break;
case 'H':
mode |= SPI_CPHA;
break;
case 'O':
mode |= SPI_CPOL;
break;
case 'L':
mode |= SPI_LSB_FIRST;
break;
case 'C':
mode |= SPI_CS_HIGH;
break;
case '3':
mode |= SPI_3WIRE;
break;
case 'N':
mode |= SPI_NO_CS;
break;
case 'R':
mode |= SPI_READY;
break;
default:
print_usage(argv[0]);
break;
int main(int argc, char *argv[])
int ret = 0;
int fd;
parse_opts(argc, argv);
fd = open(device, O_RDWR);
if (fd < 0)
pabort("can't open device");
/*
* spi mode
*/
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
pabort("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
pabort("can't get spi mode");
/*
* bits per word
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word");
/*
* max speed hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz");
printf("spi mode: %d\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
init_display(fd);
usleep(20000);
uint16_t hl[]=0X38,0X0E,0X06,0XF8,0X30,0x50,0x02;
trnsfer(fd,hl,0);
close(fd);
return ret;
【问题讨论】:
【参考方案1】:您的 LCD 模块使用 SSD1803 控制器。根据the data sheet,写操作需要传输3个字节。
第一个字节是起始字节,由 5 位“1”组成,后跟 R/W、RS 和结束位(“0”)。
接下来的 2 个字节是数据字节。低 4 位数据后跟四个“0”。然后,高 4 位数据后跟四个“0”。
第一个字节:“1” “1” “1” “1” “1” R/W("0") RS("1") “0” 第二个字节:D0 D1 D2 D3 “0” “0” “0” “0” 第三个字节:D4 D5 D6 D7 “0” “0” “0” “0”数据表中的图 7-11 说明了此操作。
另外,看起来您正在传递一个数组,但我认为传输函数只传输一个字节,因为.len = 1;
。
struct spi_ioc_transfer tr =
.tx_buf = (unsigned long)tx,
.rx_buf = 0,
.len = 1, // <- HERE
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
.cs_change=cs,
;
您想传输 3 个字节。您可以根据数组的大小修改函数并指定长度。或者,如果您在传输之间保持 CS 为低电平,您可以遍历您的数组并一个接一个地发送一个字节。
【讨论】:
我尝试了您的解决方案,但仍然没有写入 LCD。我编辑了以下部分 uint16_t hl[] = 0x38,0x0E,0x06,0xF8,0x30,0x50,0x01,0x02;转移(fd,hl,0); // 调用传输函数,其中 0xF8 是第一个字节,0x30 是低字节,0x50 是高字节。我正在尝试写“S”。 起始字节不应该是 0xFA(RS 为 1)吗?其他字节(0x38、0x0E、0x06 等)是什么?我不熟悉这个特定的 SPI 驱动程序。但是,在您的代码中,您似乎将 tx 缓冲区长度设置为 1。查看传输函数中的 spi_ioc_transfer 结构。这不是告诉驱动程序只传输一个字节吗? 非常感谢先生,您的解决方案奏效了。我可以写入 LCD。 很高兴听到你想通了!顺便说一句,如果您经常处理数字通信协议(SPI、I2C、串行等),您可能需要一个逻辑分析仪。它是一个很好的调试工具。 您好,先生,我正在尝试使用 SPI 使用相同的 LCD 屏幕写下 LCD 初始化的功能。我在尝试执行这些功能时遇到了一些问题,最初屏幕卡住了,然后如果我评论上述功能并查看会发生什么,光标仍然会闪烁。我试图从数据表的第 29,30 和 33,34,35,36,37,38,39,40 页开始执行此操作。请你帮助我好吗。我还没有写完所有的 16 个函数。但是写了几个开头的。以上是关于使用 beaglebone Black SPI 在 DIP203-6 LCD 屏幕上显示字符的主要内容,如果未能解决你的问题,请参考以下文章
Beaglebone Black – 连接 GY-91 MPU9250+BMP280 九轴传感器
Beaglebone Black教程Beaglebone Black的引脚分配