[MCU] 【年终回炉 - FRDM-MCXA156】硬件SPI驱动单色LCD显示屏

TL-LED   2026-3-8 20:45 楼主

测试使用开发板硬件SPI方式来驱动单色LCD显示屏。

 

一、硬件部分

测试使用芯片内部的LPSPI1接口,对应的电路图如下

001.png

 

需要调整R60电阻到B端,连接到P2.13端口上。

 

二、配置SPI 

在Config Tools软件中配置SPI端口和时钟

 

2.1、配置SPI端口

002.png

 

2.2、配置SPI时钟

003.png

 

三、程序部分

 

3.1、spi.c

#include "main.h"

void init_spi(void)
{
	uint32_t srcClock_Hz;
	lpspi_master_config_t masterConfig;

	/*Master config*/
	LPSPI_MasterGetDefaultConfig(&masterConfig);
	masterConfig.baudRate = TRANSFER_BAUDRATE;
	masterConfig.whichPcs = EXAMPLE_LPSPI_MASTER_PCS_FOR_INIT;
	masterConfig.pcsToSckDelayInNanoSec        = 1000000000U / (masterConfig.baudRate * 2U);
	masterConfig.lastSckToPcsDelayInNanoSec    = 1000000000U / (masterConfig.baudRate * 2U);
	masterConfig.betweenTransferDelayInNanoSec = 1000000000U / (masterConfig.baudRate * 2U);

	srcClock_Hz = LPSPI_MASTER_CLK_FREQ;
	LPSPI_MasterInit(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterConfig, srcClock_Hz);
}
uint8_t spi1_writedat(uint8_t dat)
{
	uint8_t srcBuff[2];
	uint8_t destBuff[2];
	srcBuff[0]=dat;
	lpspi_transfer_t masterXfer;
	/*Start master transfer*/
	masterXfer.txData   = srcBuff;
	masterXfer.rxData   = destBuff;
	masterXfer.dataSize = 1;
	masterXfer.configFlags =
            EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
	LPSPI_MasterTransferBlocking(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterXfer);  
	return destBuff[0];
}

3.2、spi.h

#ifndef __SPI_H
#define __SPI_H

#define LPSPI_MASTER_CLK_FREQ                 (CLOCK_GetLpspiClkFreq(1))

#define EXAMPLE_LPSPI_MASTER_BASEADDR         (LPSPI1)
#define EXAMPLE_LPSPI_MASTER_PCS_FOR_INIT     (kLPSPI_Pcs0)
#define EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER (kLPSPI_MasterPcs0)
#define TRANSFER_SIZE     64U      
#define TRANSFER_BAUDRATE 50000000U 

void init_spi(void);
uint8_t spi1_writedat(uint8_t dat);

#endif

 

3.3、fun_jlx12864.c

#include "main.h"
#include "lcd_jlx12864g/fun_jlx12864g_font.h"

//[0]0 1 2 3 ... 127	
//[1]0 1 2 3 ... 127	
//[2]0 1 2 3 ... 127	
//[3]0 1 2 3 ... 127	
//[4]0 1 2 3 ... 127	
//[5]0 1 2 3 ... 127	
//[6]0 1 2 3 ... 127	
//[7]0 1 2 3 ... 127 		   
volatile static uint8_t lcdGram[128][8];

void lcd_writebyte(uint8_t dat)
{
	spi1_writedat(dat);
}


void lcd_jlx12864g_write_cmd(uint8_t cmd)
{
	uint8_t i=0;
	lcd_jlx12864g_cs_l();
	lcd_jlx12864g_rs_l();
	
	lcd_writebyte(cmd);
}

void lcd_jlx12864g_write_dat(uint8_t dat)
{
	uint8_t i=0;

	lcd_jlx12864g_cs_l();
	lcd_jlx12864g_rs_h();
	
	lcd_writebyte(dat);
}

void lcd_refreshGram(void)
{
	uint8_t i,n;		    
	for(i=0;i<8;i++)  
	{  
		
		lcd_jlx12864g_write_cmd (0xb0+i);  //write page
		lcd_jlx12864g_write_cmd (0x00);       
		lcd_jlx12864g_write_cmd (0x10);      
		for(n=0;n<128;n++)
			lcd_jlx12864g_write_dat(lcdGram[n][i]); 
	}   
}

void lcd_clear(void)  
{  
	uint8_t i,n;  
	for(i=0;i<8;i++)
		for(n=0;n<128;n++)
			lcdGram[n][i]=0X00;  
	lcd_refreshGram(); 
}

void lcd_drawPoint(uint8_t x,uint8_t y,uint8_t t)
{
	uint8_t pos,bx,temp=0;
	if(x>127||y>63)return; 
	pos=7-y/8;
	bx=y%8;
	temp=1<<(7-bx);
	if(t)lcdGram[x][pos]|=temp;
	else lcdGram[x][pos]&=~temp;	    
}

//读点 
//x:0~127
//y:0~63
uint8_t lcd_readPoint(uint8_t x,uint8_t y)
{
	uint8_t pos,bx,temp=0x00;
	//x = 127-x;
	y = 63-y;
	pos=y/8;
	bx=y%8;
	temp=1<<bx;
  if(temp&lcdGram[x][pos]) return 1;
	return 0;
}

//x1,y1,x2,y2 填充区域的对角坐标
//确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63	 	 
//dot:0,清空;1,填充	  
void lcd_fill(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t dot)  
{  
	uint8_t x,y;  
	for(x=x1;x<=x2;x++)
		for(y=y1;y<=y2;y++)
			lcd_drawPoint(x,y,dot);											    
//	oled_refreshGram();//更新显示
}


//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//f_w:字宽
//f_h:字高
//mode:0,反白显示;1,正常显示					 
void lcd_showChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t f_w,uint8_t f_h,uint8_t mode)
{      			    
	uint8_t temp,t,t1;
	uint8_t y0=y;	
	uint8_t csize=(f_h/8+((f_h%8)?1:0))*f_w; 
	chr=chr-' ';  
	for(t=0;t<csize;t++)
	{   
		if(f_w==6&&f_h==8)temp=asc2_0608[chr][t];		 
		else if(f_w==6&&f_h==12)temp=asc2_0612[chr][t];	 
		else if(f_w==12&&f_h==24)temp=asc2_1224[chr][t]; 
		else return;	 
		for(t1=0;t1<8;t1++)
		{
			if(temp&0x80)lcd_drawPoint(x,y,mode);
			else lcd_drawPoint(x,y,!mode);
			temp<<=1;
			y++;
			if((y-y0)==f_h)
			{
				y=y0;
				x++;
				break;
			}
		}  	 
	}     
}

//m^n函数
uint32_t mypow(uint8_t m,uint8_t n)
{
	uint32_t result=1;	 
	while(n--)result*=m;    
	return result;
}

//显示2个数字
//x,y :起点坐标	 
//len :数字的位数
//f_w:字宽
//f_h:字高
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);	 		  
void lcd_showNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t f_w,uint8_t f_h)
{         	
	uint8_t t,temp;
	uint8_t enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/mypow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				lcd_showChar(x+(f_w)*t,y,' ',f_w,f_h,1);
				continue;
			}
			else 
				enshow=1; 
		}
	 	lcd_showChar(x+(f_w)*t,y,temp+'0',f_w,f_h,1); 
	}
} 

//显示字符串
//x,y:起点坐标  
//f_w:字宽
//f_h:字高
//*p:字符串起始地址 
void lcd_showString(uint8_t x,uint8_t y,const uint8_t *p,uint8_t f_w,uint8_t f_h)
{	
    while((*p<='~')&&(*p>=' ')) 
    {       
        if(x>(128-(f_w))){x=0;y+=f_h;}
        if(y>(64-f_h)){y=x=0;lcd_clear();}
        lcd_showChar(x,y,*p,f_w,f_h,1);	 
        x+=f_w;
        p++;
    }  
	
}

//显示图片
//x,y:起点坐标  
//p_w:图片宽(单位像素)
//p_h:图片高(单位像素)
//*p:图片起始地址 
void lcd_showPicture(uint8_t x,uint8_t y,const uint8_t *p,uint8_t p_w,uint8_t p_h)
{	
	uint8_t temp,i,col,row;
	uint8_t y0=y;
	uint8_t width=p_w;
	if(x+p_w>128)width=128-p_w;//实际显示宽度
	uint8_t high=p_h;
	if(y+p_h>64)high=64-p_h;//实际显示高度
	uint8_t exp_col_bytes=(p_h/8+((p_h%8)?1:0));//显示一列的字节数
	uint8_t act_col_bytes=(high/8+((high%8)?1:0));//实际显示一列的字节数
	
	for(row=0;row<width;row++)//列++
	{
		for(col=0;col<act_col_bytes;col++)//显示一列
		{   
			temp = p[col+row*exp_col_bytes];
			for(i=0;i<8;i++)
			{
				if(temp&0x80)lcd_drawPoint(x,y,1);
				else lcd_drawPoint(x,y,0);
				temp<<=1;
				y++;
				if((y-y0)==high)
				{
					y=y0;
					x++;
					break;
				}		
			} 
		}
	}		
}

void init_lcd_jlx12864g(void)
{
	lcd_jlx12864g_cs_h();
	lcd_jlx12864g_rst_l();
	SysTick_Delay_ms(200);
	lcd_jlx12864g_rst_h();
	SysTick_Delay_ms(200);
	lcd_jlx12864g_write_cmd(0xe2);
	lcd_jlx12864g_write_cmd(0x2c);
	lcd_jlx12864g_write_cmd(0x2e);
	lcd_jlx12864g_write_cmd(0x2f);
	lcd_jlx12864g_write_cmd(0x23);
	lcd_jlx12864g_write_cmd(0x81);
	lcd_jlx12864g_write_cmd(0x28);
	lcd_jlx12864g_write_cmd(0xa2);
	lcd_jlx12864g_write_cmd(0xc0);
	lcd_jlx12864g_write_cmd(0xa0);
	lcd_jlx12864g_write_cmd(0x40);
	lcd_jlx12864g_write_cmd(0xaf);
	lcd_clear();
	//lcd_jlx12864g_bk_on();
}

 

3.4、main.c

#include "main.h"

int main(void)
{
	BOARD_InitBootPins();
	BOARD_InitBootClocks();
	BOARD_InitDebugConsole();
	BOARD_InitBootPeripherals();
	
	printf("zhang\r\n");

	SysTick_Init();
	init_led();
	//init_key();
	//OLED_Init();
	//oled_test();
	
	init_spi();
	init_lcd_jlx12864g();
	
    lcd_showString(0,0, (uint8_t*)"MCXA156_BOARD_TEST",6,12);
    lcd_showString(0,13,(uint8_t*)"MCU:MCXA156",6,12);
    lcd_showString(0,26,(uint8_t*)"JLX12864G-SPI",6,12);
    lcd_showString(0,39,(uint8_t*)"2026-03-08",6,12);
    lcd_refreshGram();
	while (1)
	{
		SysTick_Delay_ms(200);
		led_red_tog();
	}
}

 

四、运行结果

 

下载程序后,显示屏显示如下

spi-lcd.jpg

 

回复评论 (4)

可款我也用,价格很有优势,

但不是很稳定,有时启动初始化失败。

چوآن شـين
点赞  2026-3-9 19:27
引用: Gen_X 发表于 2026-3-9 19:27 可款我也用,价格很有优势, 但不是很稳定,有时启动初始化失败。

这个还没有发现。

点赞  2026-3-9 21:15
这个屏看起来有点年代感了,大佬存货多呀!
点赞 (1) 2026-3-10 07:30
引用: lugl4313820 发表于 2026-3-10 07:30 这个屏看起来有点年代感了,大佬存货多呀!

从旧的东东上面拆的屏幕,做的LCD模块。

点赞  2026-3-10 08:27
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复