3线硬件SPI+DMA驱动 HX8347 TFT屏-快速显示文字

 本文实现DMA快速显示文字

汉字点阵通常是16*16点阵,那么用DMA一次性显示汉字,应该至少申请480*16个字节的空间,用于显示一行文字,其中480是屏幕一行用DMA驱动所需内存。

一、 源码

HX8347.h

#ifndef USER_HX8347_H_
#define USER_HX8347_H_#define SPI_hardware
#define SPI_hardware_dma#define Buf_Size 480*16#define X_MAX_PIXEL 240
#define Y_MAX_PIXEL 320#define RED     0xf800
#define GREEN   0x07e0
#define BLUE    0x001f
#define WHITE   0xffff
#define BLACK   0x0000
#define YELLOW  0xFFE0
#define GRAY0   0xEF7D      //灰色0 3165 00110 001011 00101
#define GRAY1   0x8410          //灰色1      00000 000000 00000
#define GRAY2   0x4208          //灰色2  1111111111011111#ifdef SPI_hardware#define LCD_CS          GPIO_Pin_0  // CS:PA0#define LCD_SDA         GPIO_Pin_7  // SDA:PA7  SPI1 //硬件SPI实现,不用人工处理#define LCD_SCL         GPIO_Pin_5  // SCL:PA5  SPI1 //硬件SPI实现,不用人工处理#define LCD_RST         GPIO_Pin_4  // RST:PA4
#else#define LCD_CS          GPIO_Pin_0  // CS:PA0#define LCD_SDA         GPIO_Pin_1  // SDA:PA1#define LCD_SCL         GPIO_Pin_3  // SCL:PA3#define LCD_RST         GPIO_Pin_4  // RST:PA4
#endif#define LCD_SCL_SET GPIO_WriteBit(GPIOA, LCD_SCL,Bit_SET)
#define LCD_SDA_SET GPIO_WriteBit(GPIOA, LCD_SDA,Bit_SET)
#define LCD_CS_SET  GPIO_WriteBit(GPIOA, LCD_CS,Bit_SET)
#define LCD_RST_SET GPIO_WriteBit(GPIOA, LCD_RST,Bit_SET)#define LCD_SCL_CLR GPIO_WriteBit(GPIOA, LCD_SCL,Bit_RESET)
#define LCD_SDA_CLR GPIO_WriteBit(GPIOA, LCD_SDA,Bit_RESET)
#define LCD_CS_CLR  GPIO_WriteBit(GPIOA, LCD_CS,Bit_RESET)
#define LCD_RST_CLR GPIO_WriteBit(GPIOA, LCD_RST,Bit_RESET)void LCD_GPIO_Init(void);
void Lcd_WriteIndex(unsigned char Index);
void Lcd_WriteData(unsigned char Data);
void LCD_WriteData_16Bit(unsigned int Data);
void Lcd_Write_REG(unsigned char Index,unsigned char Data);
void LCD_Init(void);
void Lcd_Clear(unsigned int Color);
void FillRect(u16 x1, u16 y1, u16 x2, u16 y2, u16 color);
void FillRect_DMA(u16 color);void Gui_DrawFont_GBK16(unsigned int x, unsigned int y, unsigned int fc, unsigned int bc, unsigned char *s);
void Gui_DrawFont_GBK16_DMA(unsigned int x, unsigned int y, unsigned int fc, unsigned int bc,unsigned char *s);#endif /* USER_HX8347_H_ */

HX8347.c

#include "debug.h"
#include "HX8347.h"
#include "font.h"extern unsigned char TxData[];
extern void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx);void LCD_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure = {0};RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
#ifdef SPI_hardwareGPIO_InitStructure.GPIO_Pin = LCD_CS|LCD_RST;
#elseGPIO_InitStructure.GPIO_Pin = LCD_SCL|LCD_SDA|LCD_CS|LCD_RST;
#endifGPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);
}//向SPI总线传输一个8位数据void  SPI_WriteData(unsigned char Data)
{
#ifdef SPI_hardwareSPI_I2S_SendData( SPI1, Data);while( SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_TXE ) == RESET );//Delay_Us(1);uint32_t i;SysTick->SR &= ~(1 << 0);i = 8;SysTick->CMP = i;SysTick->CTLR |= (1 << 4);SysTick->CTLR |= (1 << 5) | (1 << 0);while((SysTick->SR & (1 << 0)) != (1 << 0));SysTick->CTLR &= ~(1 << 0);#elseunsigned char i=0;for(i=8;i>0;i--){if(Data&0x80)LCD_SDA_SET; //输出数据else LCD_SDA_CLR;LCD_SCL_CLR;LCD_SCL_SET;Data<<=1;}
#endif
}//向液晶屏写一个8位指令void Lcd_WriteIndex(unsigned char Index)
{//SPI 写命令时序开始LCD_CS_CLR;SPI_WriteData(0x70);SPI_WriteData(Index);LCD_CS_SET;
}//向液晶屏写一个8位数据void Lcd_WriteData(unsigned char Data)
{LCD_CS_CLR;SPI_WriteData(0x72);SPI_WriteData(Data);LCD_CS_SET;
}//向液晶屏写一个16位数据
void LCD_WriteData_16Bit(unsigned int Data)
{LCD_CS_CLR;SPI_WriteData(0x72);SPI_WriteData(Data>>8);SPI_WriteData(Data);LCD_CS_SET;
}void Lcd_Write_REG(unsigned char Index,unsigned char Data)
{Lcd_WriteIndex(Index);Lcd_WriteData(Data);
}void Lcd_Reset(void)
{LCD_RST_CLR;Delay_Ms(50);LCD_RST_SET;Delay_Ms(50);
}//  set region to paint
void LCD_SetWindow(unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2)
{//SCLcd_Write_REG(0x02,x1>>8);       // Column address start2Lcd_Write_REG(0x03,(u8)x1);          // Column address start1//ECLcd_Write_REG(0x04,x2>>8);       // Column address end2Lcd_Write_REG(0x05,(u8)x2);          // Column address end1//SPLcd_Write_REG(0x06,y1>>8);       // Row address start2Lcd_Write_REG(0x07,(u8)y1);          // Row address start1//EPLcd_Write_REG(0x08,y2>>8);       // Row address end2Lcd_Write_REG(0x09,(u8)y2);          // Row address end1//写0x22到index register,那么下次send data就会直接被写到graphic ramLcd_WriteIndex(0x22);
}void FillRect(u16 x1, u16 y1, u16 x2, u16 y2, u16 color)
{LCD_SetWindow(x1, y1,x2,y2);x2 = x2 - x1 + 1;y2 = y2 - y1 + 1;LCD_CS_CLR;SPI_WriteData(0x72);for(x1 = x2; x1 != 0 ; x1--){for (y1 = y2;y1 != 0 ;y1--){SPI_WriteData(color>>8);SPI_WriteData(color);}}LCD_CS_SET;
}void FillRect_DMA(u16 color)
{int16_t j;LCD_SetWindow(0, 0,239,319);LCD_CS_CLR;SPI_WriteData(0x72);for(j=0 ;j<Buf_Size;){TxData[j] = color>>8;TxData[j+1] = color;j += 2;}for(j = 0 ; j<320/(Buf_Size/480) ; j++){SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);MYDMA_Enable(DMA1_Channel3);while(1){if(DMA_GetFlagStatus(DMA1_FLAG_TC3)!=RESET){DMA_ClearFlag(DMA1_FLAG_TC3);break;}}}LCD_CS_SET;
}void LCD_Init(void)
{//LCD_GPIO_Init();Lcd_Reset();Lcd_Write_REG(0x18,0x88);        //UADJ 75HzLcd_Write_REG(0x19,0x01);        //OSC_EN='1', start Osc//Power Voltage SettingLcd_Write_REG(0x1B,0x1e); //VRH=4.60V   0x1eLcd_Write_REG(0x1C,0x04); //AP Crosstalk    04Lcd_Write_REG(0x1A,0x01); //BT (VGH~15V,VGL~-10V,DDVDH~5V)   0x01Lcd_Write_REG(0x24,0x21); //VMH 27   0x38Lcd_Write_REG(0x25,0x5F); //VML//VCOM offsetLcd_Write_REG(0x23,0x8C); //for Flicker adjustLcd_Write_REG(0x1F,0x88);// GAS=1, VOMG=00, PON=0, DK=1, XDK=0, DVDH_TRI=0, STB=0Delay_Ms(50);Lcd_Write_REG(0x1F,0x80);// GAS=1, VOMG=00, PON=0, DK=0, XDK=0, DVDH_TRI=0, STB=0Delay_Ms(50);Lcd_Write_REG(0x1F,0x90);// GAS=1, VOMG=00, PON=1, DK=0, XDK=0, DVDH_TRI=0, STB=0Delay_Ms(50);Lcd_Write_REG(0x1F,0xD0);// GAS=1, VOMG=10, PON=1, DK=0, XDK=0, DDVDH_TRI=0, STB=0Delay_Ms(50);//Display ON SettingLcd_Write_REG(0x28,0x38);   //GON=1, DTE=1, D=1000Delay_Ms(50);Lcd_Write_REG(0x28,0x3C);   //GON=1, DTE=1, D=1100Lcd_Write_REG(0x36,0x09);   //REV, BGRLcd_Write_REG(0x17,0x05);  //16BIT/PIXEL//Gamma 2.2 SettingLcd_Write_REG(0x40,0x00); //Lcd_Write_REG(0x41,0x00); //Lcd_Write_REG(0x42,0x00); //Lcd_Write_REG(0x43,0x11); //Lcd_Write_REG(0x44,0x0e); //Lcd_Write_REG(0x45,0x23); //Lcd_Write_REG(0x46,0x08); //Lcd_Write_REG(0x47,0x53); //Lcd_Write_REG(0x48,0x03); //Lcd_Write_REG(0x49,0x11); //Lcd_Write_REG(0x4A,0x18); //Lcd_Write_REG(0x4B,0x1a); //Lcd_Write_REG(0x4C,0x16); //Lcd_Write_REG(0x50,0x1c); //Lcd_Write_REG(0x51,0x31); //Lcd_Write_REG(0x52,0x2e); //Lcd_Write_REG(0x53,0x3f); //Lcd_Write_REG(0x54,0x3f); //Lcd_Write_REG(0x55,0x3f); //Lcd_Write_REG(0x56,0x2c); //Lcd_Write_REG(0x57,0x77); //Lcd_Write_REG(0x58,0x09); //Lcd_Write_REG(0x59,0x05); //Lcd_Write_REG(0x5A,0x07); //Lcd_Write_REG(0x5B,0x0e); //Lcd_Write_REG(0x5C,0x1c); //Lcd_Write_REG(0x5D,0x88); //Delay_Ms(100);FillRect(0, 0, 239, 319, RED );
}/*************************************************
函数名:LCD_DrawPoint
功能:画一个点
入口参数:无
返回值:无
*************************************************/
void Gui_DrawPoint(unsigned int x,unsigned int y,unsigned int Data)
{LCD_SetWindow(x,y,x+1,y+1);LCD_WriteData_16Bit(Data);
}void Gui_DrawPoint_DMA(unsigned int x,unsigned int y,unsigned int Data)
{//LCD_SetWindow(x,y,x+1,y+1);//LCD_WriteData_16Bit(Data);TxData[2*x+y*480]=Data>>8;TxData[2*x+y*480+1]=Data;}void DMA_BUFFER_RESET(unsigned int bc)
{unsigned int j;for(j=0 ;j<Buf_Size;){TxData[j] = bc>>8;TxData[j+1] = bc;j += 2;}
}void Gui_DrawFont_GBK16(unsigned int x, unsigned int y, unsigned int fc, unsigned int bc,unsigned char *s)
{unsigned char i,j;unsigned short k,x0;x0=x;while(*s){if((*s) < 128){k=*s;if (k==13){x=x0;y+=16;}else{if (k>32) k-=32; else k=0;for(i=0;i<16;i++)for(j=0;j<8;j++){if(asc16[k*16+i]&(0x80>>j)) Gui_DrawPoint(x+j,y+i,fc);else{if (fc!=bc) Gui_DrawPoint(x+j,y+i,bc);}}x+=8;}s++;}else{for (k=0;k<hz16_num;k++){if ((hz16[k].Index[0]==*(s))&&(hz16[k].Index[1]==*(s+1))){for(i=0;i<16;i++){for(j=0;j<8;j++){if(hz16[k].Msk[i*2]&(0x80>>j))  Gui_DrawPoint(x+j,y+i,fc);else {if (fc!=bc) Gui_DrawPoint(x+j,y+i,bc);}}for(j=0;j<8;j++){if(hz16[k].Msk[i*2+1]&(0x80>>j))    Gui_DrawPoint(x+j+8,y+i,fc);else{if (fc!=bc) Gui_DrawPoint(x+j+8,y+i,bc);}}}}}s+=2;x+=16;}}
}void Gui_DrawFont_GBK16_DMA(unsigned int x, unsigned int y, unsigned int fc, unsigned int bc,unsigned char *s)
{unsigned char i,j;unsigned short k,x0,y0;x0=x;y0=y;x=0;y=0;DMA_BUFFER_RESET(bc);       //清缓存while(*s){if((*s) < 128){k=*s;if (k==13){x=x0;y+=16;}else{if (k>32) k-=32; else k=0;for(i=0;i<16;i++)for(j=0;j<8;j++){if(asc16[k*16+i]&(0x80>>j)) Gui_DrawPoint_DMA(x+j,y+i,fc);else{if (fc!=bc) Gui_DrawPoint_DMA(x+j,y+i,bc);}}x+=8;}s++;}else{for (k=0;k<hz16_num;k++){if ((hz16[k].Index[0]==*(s))&&(hz16[k].Index[1]==*(s+1))){for(i=0;i<16;i++){for(j=0;j<8;j++){if(hz16[k].Msk[i*2]&(0x80>>j))  Gui_DrawPoint_DMA(x+j,y+i,fc);else {if (fc!=bc) Gui_DrawPoint_DMA(x+j,y+i,bc);}}for(j=0;j<8;j++){if(hz16[k].Msk[i*2+1]&(0x80>>j))   Gui_DrawPoint_DMA(x+j+8,y+i,fc);else{if (fc!=bc) Gui_DrawPoint_DMA(x+j+8,y+i,bc);}}}}}s+=2;x+=16;}}LCD_SetWindow(0,y0,239,y0+16);LCD_CS_CLR;SPI_WriteData(0x72);SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);MYDMA_Enable(DMA1_Channel3);while(1){if(DMA_GetFlagStatus(DMA1_FLAG_TC3)!=RESET){DMA_ClearFlag(DMA1_FLAG_TC3);break;}}LCD_CS_SET;}

main.c

/********************************** (C) COPYRIGHT *******************************
* File Name          : main.c
* Author             : WCH
* Version            : V1.0.0
* Date               : 2021/06/06
* Description        : Main program body.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for 
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************//**@NoteGPIO routine:PA0 push-pull output.*/#include "debug.h"
#include "HX8347.h"/* Global define *//* Global Variable */unsigned char TxData[Buf_Size]={0};
u16 DMA1_MEM_LEN;/********************************************************************** @fn      GPIO_Toggle_INIT** @brief   Initializes GPIOA.0** @return  none*/
void GPIO_Toggle_INIT(void)
{GPIO_InitTypeDef GPIO_InitStructure = {0};RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);
}void SPI_1Lines_HalfDuplex_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure={0};SPI_InitTypeDef SPI_InitStructure={0};RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1|RCC_APB2Periph_GPIOA, ENABLE );GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init( GPIOA, &GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init( GPIOA, &GPIO_InitStructure );SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;         //在空闲状态下,时钟线保持高电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;        //数据在时钟的上升沿被传输。SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init( SPI1, &SPI_InitStructure );SPI_Cmd( SPI1, ENABLE );
}//使能dma1的通道3,因为spi输出对应的是此通道
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{DMA_Cmd(DMA_CHx, DISABLE );DMA_SetCurrDataCounter(DMA1_Channel3,DMA1_MEM_LEN);DMA_Cmd(DMA_CHx, ENABLE);
}/********************************************************************** @fn      DMA_Tx_Init** @brief   Initializes the DMAy Channelx configuration.** @param   DMA_CHx - x can be 1 to 7.*          ppadr - Peripheral base address.*          memadr - Memory base address.*          bufsize - DMA channel buffer size.** @return  none*/
void DMA_Tx_Init( DMA_Channel_TypeDef* DMA_CHx, u32 ppadr, u32 memadr, u16 bufsize)
{DMA_InitTypeDef DMA_InitStructure={0};RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE );DMA_DeInit(DMA_CHx);DMA1_MEM_LEN=bufsize;DMA_InitStructure.DMA_PeripheralBaseAddr = ppadr;DMA_InitStructure.DMA_MemoryBaseAddr = memadr;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;DMA_InitStructure.DMA_BufferSize = bufsize;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init( DMA_CHx, &DMA_InitStructure );
}/********************************************************************** @fn      main** @brief   Main program.** @return  none*/
int main(void)
{u8 i = 0;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);SystemCoreClockUpdate();Delay_Init();USART_Printf_Init(115200);	printf("SystemClk:%d\r\n", SystemCoreClock);printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );printf("GPIO Toggle TEST\r\n");GPIO_Toggle_INIT();LCD_GPIO_Init();
#ifdef SPI_hardwareprintf("SPI_HARDWARE");SPI_1Lines_HalfDuplex_Init();
#ifdef SPI_hardware_dmaprintf("SPI_HARDWARE_DMA");DMA_Tx_Init( DMA1_Channel3, (u32)&SPI1->DATAR, (u32)TxData, Buf_Size );DMA_Cmd( DMA1_Channel3, ENABLE );
#endif
#elseprintf("SPI_SOFTWARE");
#endifLCD_Init();GPIO_WriteBit(GPIOB, GPIO_Pin_13,Bit_RESET);while(1){Delay_Ms(1000);FillRect_DMA(GREEN);Gui_DrawFont_GBK16_DMA(0,5,BLACK,GREEN,"HELLO world");Gui_DrawFont_GBK16_DMA(0,25,RED,GREEN,"LCD OK DISPLAY");Gui_DrawFont_GBK16_DMA(0,45,RED,GREEN,"智能物联红外测温系统通过人数");Gui_DrawFont_GBK16_DMA(0,65,RED,GREEN,"报警人数人体温度环境表面距离");Gui_DrawFont_GBK16_DMA(0,85,RED,GREEN,"网络连接中.温度气象站雨量风速");Gui_DrawFont_GBK16_DMA(0,105,RED,GREEN,"创新实验平台℃");Delay_Ms(2000);FillRect_DMA(RED);Delay_Ms(1000);FillRect_DMA(BLUE);Gui_DrawFont_GBK16_DMA(0,5,WHITE,BLUE,"HELLO world");Gui_DrawFont_GBK16_DMA(0,25,WHITE,BLUE,"LCD OK DISPLAY");Gui_DrawFont_GBK16_DMA(0,45,WHITE,BLUE,"智能物联红外测温系统通过人数");Gui_DrawFont_GBK16_DMA(0,65,WHITE,BLUE,"报警人数人体温度环境表面距离");Gui_DrawFont_GBK16_DMA(0,85,WHITE,BLUE,"网络连接中.温度气象站雨量风速");Gui_DrawFont_GBK16_DMA(0,105,WHITE,BLUE,"创新实验平台℃");Delay_Ms(1000);FillRect_DMA(YELLOW);Delay_Ms(1000);FillRect(0, 0, 239, 63, RED );Gui_DrawFont_GBK16(15,5,BLACK,GRAY0,"HELLO world");Gui_DrawFont_GBK16(15,25,RED,GRAY0,"LCD OK DISPLAY");Gui_DrawFont_GBK16(15,45,RED,GRAY0,"智能物联红外测温系统通过人数");Gui_DrawFont_GBK16(15,65,RED,GRAY0,"报警人数人体温度环境表面距离");Gui_DrawFont_GBK16(15,85,RED,GRAY0,"网络连接中.温度气象站雨量风速");Gui_DrawFont_GBK16(15,105,RED,GRAY0,"创新实验平台℃");Delay_Ms(1000);GPIO_WriteBit(GPIOB, GPIO_Pin_13, (i == 0) ? (i = Bit_SET) : (i = Bit_RESET));printf( "GPIOB:%d\r\n", i);FillRect(0, 0, 239, 319, RED );Delay_Ms(1000);FillRect(0, 0, 239, 319, GREEN );Delay_Ms(1000);FillRect(0, 0, 239, 319, BLUE );FillRect(50, 50, 100, 100, RED );}
}

二、说明

 1、增加了 Gui_DrawPoint_DMA(unsigned int x,unsigned int y,unsigned int Data)向DMA内存画点的功能

void Gui_DrawPoint_DMA(unsigned int x,unsigned int y,unsigned int Data)
{
    TxData[2*x+y*480]=Data>>8;
    TxData[2*x+y*480+1]=Data;

}

2、增加了void DMA_BUFFER_RESET(unsigned int bc),用于清空DMA内存

void DMA_BUFFER_RESET(unsigned int bc)
{
    unsigned int j;
    for(j=0 ;j<Buf_Size;){
        TxData[j] = bc>>8;
        TxData[j+1] = bc;
     j += 2;
    }

3、增加了Gui_DrawFont_GBK16_DMA(unsigned int x, unsigned int y, unsigned int fc, unsigned int bc,unsigned char *s)。用于处理字符串并以DMA方式输出到屏幕。

void Gui_DrawFont_GBK16_DMA(unsigned int x, unsigned int y, unsigned int fc, unsigned int bc,unsigned char *s)
{
    unsigned char i,j;
    unsigned short k,x0,y0;
    x0=x;
    y0=y;
    x=0;
    y=0;

    DMA_BUFFER_RESET(bc);       //清缓存
    while(*s)
    {

        if((*s) < 128)
        {
            k=*s;
            if (k==13)
            {
                x=x0;
                y+=16;
            }
            else
            {
                if (k>32) k-=32; else k=0;

                for(i=0;i<16;i++)
                for(j=0;j<8;j++)
                    {
                        if(asc16[k*16+i]&(0x80>>j)) Gui_DrawPoint_DMA(x+j,y+i,fc);
                        else
                        {
                            if (fc!=bc) Gui_DrawPoint_DMA(x+j,y+i,bc);
                        }
                    }
                x+=8;
            }
            s++;
        }

        else
        {


            for (k=0;k<hz16_num;k++)
            {
              if ((hz16[k].Index[0]==*(s))&&(hz16[k].Index[1]==*(s+1)))
              {

                    for(i=0;i<16;i++)
                    {
                        for(j=0;j<8;j++)
                            {
                                if(hz16[k].Msk[i*2]&(0x80>>j))  Gui_DrawPoint_DMA(x+j,y+i,fc);
                                else {
                                    if (fc!=bc) Gui_DrawPoint_DMA(x+j,y+i,bc);
                                }
                            }
                        for(j=0;j<8;j++)
                            {
                                if(hz16[k].Msk[i*2+1]&(0x80>>j))   Gui_DrawPoint_DMA(x+j+8,y+i,fc);
                                else
                                {
                                    if (fc!=bc) Gui_DrawPoint_DMA(x+j+8,y+i,bc);
                                }
                            }
                    }
                }
              }
            s+=2;x+=16;
        }

    }

    LCD_SetWindow(0,y0,239,y0+16);
    LCD_CS_CLR;
    SPI_WriteData(0x72);


    SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);
       MYDMA_Enable(DMA1_Channel3);

       while(1){
           if(DMA_GetFlagStatus(DMA1_FLAG_TC3)!=RESET)
           {
               DMA_ClearFlag(DMA1_FLAG_TC3);
               break;
           }
       }
    LCD_CS_SET;

}

三、总结

1、申请的DMA空间为480*16,对应于屏幕是一个240*16的长条空间。也就是每次向屏幕刷一个 240*16范围,对应文字就是一行。改变起始位置,就可以在其他地方再刷一行。

DMA快速显示文字

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/137266.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

回归预测 | Matlab实现PCA-PLS主成分降维结合偏最小二乘回归预测

回归预测 | Matlab实现PCA-PLS主成分降维结合偏最小二乘回归预测 目录 回归预测 | Matlab实现PCA-PLS主成分降维结合偏最小二乘回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现PCA-PLS主成分降维结合偏小二乘回归预测&#xff08;完整源码和数据) 1.输…

2023年9月少儿编程 中国电子学会图形化编程等级考试Scratch编程二级真题解析(选择题)

2023年9月scratch编程等级考试二级真题 选择题(共25题,每题2分,共50分) 1、点击绿旗,运行程序后,舞台上的图形是 A、画笔粗细为4的三角形 B、画笔粗细为5的六边形 C、画笔粗细为4的六角形 D、画笔粗细为5的三角形 答案:D 考点分析:考查积木综合使用,重点考查画笔…

伪造referer [极客大挑战 2019]Http1

打开题目 没有发现什么&#xff0c;我们查看源代码 在这里我们发现了提示 访问一下页面得到 提示说不能来自于https://Sycsecret.buuoj.cn&#xff0c;我们尝试访问一下这个url 发现访问不了 我们bp抓包一下 伪造个referer头 referer:https://Sycsecret.buuoj.cn 发包过去…

【js逆向实战】某sakura动漫视频逆向

写在前面 再写一个逆向实战&#xff0c;后面写点爬虫程序来实现一下。 网站简介与逆向目标 经典的一个视频网站&#xff0c;大多数视频网站走的是M3U8协议&#xff0c;就是一个分段传输&#xff0c;其实这里就有两个分支。 通过传统的m3u8协议&#xff0c;我们可以直接进行分…

如何申请QQ邮箱的SMTP密钥简洁版

QQ 邮箱的 SMTP 密钥通常称为"SMTP 授权码"&#xff0c;你可以按照以下步骤找到它&#xff1a; 1.登录 QQ 邮箱&#xff1a;打开 QQ 邮箱登录页面&#xff0c;并使用你的 QQ 账号和密码登录。 2.进入设置页面&#xff1a;在 QQ 邮箱页面中&#xff0c;点击顶部的&q…

MySQL篇之mysql主从集群搭建

一、MySQL集群架构的介绍 我们在使用MySQL数据库的时候&#xff0c;只是一个单机的数据库服务。在实际的生产环境中&#xff0c;数据量可能会非常庞大&#xff0c;这样单机服务的MySQL在使用的时候&#xff0c;性能会受到影响。并且单机的数据安全想也会受到影响。因此在生产黄…

制作一个模板三

您已经看到了Jinja2在呈现过程中如何用实际值替换占位符&#xff0c;但这只是Jinja2在模板文件中支持的众多强大操作之一。例如&#xff0c;模板还支持在{%…%}块。下一个版本的index.html模板增加了一个条件语句: app/templates/index.html: <!doctype html> <htm…

快速开发一个简单实用的MES系统?

题主在一个光伏组件工厂做生产管理&#xff0c;但工厂竟然没有MES系统&#xff0c;于是想自己开发一个简单的MES系统。那么我们来看看题主对于开发MES系统的要求—— 对系统&#xff1a;每一个产品都有一个条形码&#xff0c;希望系统可以追踪生产计划下的产品的生产状态&…

RPA在财务预测和分析中的应用

在现代企业管理中&#xff0c;财务数据分析是决策制定和战略规划的关键环节。大数据的兴起带来财务数据的复杂性和数量不断增加&#xff0c;企业为此消耗了大量人力和物力。随着当今数字化、智能化时代的到来&#xff0c;越来越多企业引进RPA技术来提高工作效率&#xff0c;实现…

LeetCode算法心得——全排列(回溯型排列)

大家好&#xff0c;我是晴天学长&#xff0c;排列型的回溯&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1f4aa; 1) .全排列 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按…

JVM垃圾回收机制

JVM 可达性分析法 1. 垃圾回收器的基本概念 什么是垃圾回收器&#xff1a;JVM 为 Java 提供了垃圾回收机制&#xff0c;其实是一种偏自动的内存管理机制。简单来说&#xff0c;垃圾回收器会自动追踪所有正在使用的对象&#xff0c;并将其余未被使用的对象标记为垃圾&#xff…

【poi导出excel模板——通过建造者模式+策略模式+函数式接口实现】

poi导出excel模板——通过建造者模式策略模式函数式接口实现 poi导出excel示例优化思路代码实现补充建造者模式策略模式 poi导出excel示例 首先我们现看一下poi如何导出excel&#xff0c;这里举个例子&#xff1a;目前想要导出一个Map<sex,List>信息&#xff0c;sex作为…

独立站运营和facebook投放怎么做

独立站运营和Facebook投放可以采取以下步骤&#xff1a; 制定投放目标&#xff1a;独立站卖家应该选择最适合与自己投放需求匹配的目标&#xff0c;比如需要提高内容参与度等。选择消费受众&#xff1a;根据年龄、性别、教育、地区、兴趣爱好、设备型号、过往购买等行为来判定…

idea2023如何查看被使用上下文关系

1.接口查看实现类&#xff0c;实现类查看接口 查看接口所有实现类 根据类里面的方法查看被覆盖的接口中的方法 2.查看方法、类被调用 3.查看类的继承关系

xcorr函数的用法和程序举例

xcorr函数的用法和程序举例 xcorr函数返回两个离散时间序列的互相关。互相关测量向量 x 和移位&#xff08;滞后&#xff09;副本向量y 的之间的相似性&#xff0c;形式为滞后的函数。如果 x 和 y 的长度不同&#xff0c;函数会在较短向量的末尾添加零&#xff0c;使其长度与另…

Flutter:安装依赖报错doesn‘t support null safety

项目中需要引用http依赖&#xff0c;在pubspec.yaml文件中添加如下信息&#xff1a; 当同步时&#xff0c;报错信息如下&#xff1a; [myflutter] flutter pub upgrade Resolving dependencies... The current Dart SDK version is 3.1.3. Because myflutter depends on http &…

Harmony 应用开发的知识储备

Harmony 应用开发的知识储备 前言正文一、DevEco Studio版本二、手机版本① 环境变量 三、API版本四、开发语言五、运行调试 前言 这里先说明一点&#xff0c;如果你对Android应用开发很熟悉&#xff0c;那么做Harmony应用开发也可以驾轻就熟&#xff0c;只不过在此之前你需要知…

TensorFlow学习笔记--(2)张量的常用运算函数

张量的取值函数 求张量的平均值: tf.reduce.mean(%张量名%)求张量的最小值:tf.reduce_min(%张量名%)求张量的最大值:tf.reduce_max(%张量名%)求张量的和:tf.reduce_sum(%张量名%)其次,对于上述所有操作 都可在函数后添加一个新的参数 axis%维度% axis0 代表第一维度 axis1 代表…

无人机航迹规划:五种最新智能优化算法(COA、SWO、KOA、GRO、LO)求解无人机路径规划MATLAB

一、五种算法&#xff08;LSO、SWO、KOA、GRO、LO&#xff09;简介 1、小龙虾优化算法COA 小龙虾优化算法&#xff08;Crayfsh optimization algorithm&#xff0c;COA&#xff09;由Jia Heming 等人于2023年提出&#xff0c;该算法模拟小龙虾的避暑、竞争和觅食行为&#xf…

springboot整合ELK

ELK是一种强大的分布式日志管理解决方案&#xff0c;它由三个核心组件组成&#xff1a; Elasticsearch&#xff1a;作为分布式搜索和分析引擎&#xff0c;Elasticsearch能够快速地存储、搜索和分析大量的日志数据&#xff0c;帮助用户轻松地找到所需的信息。 Logstash&#xff…