你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32的HAL库,如何对高八位和低八位同时赋值和操作?

[复制链接]
龙龍 提问时间:2024-8-4 23:16 / 未解决

如图,想用STM32F103C8T6点亮一个16PIN的并行输出LCD12864屏幕,但是引脚设置问题,D0~D7没放在一起,想同时操作D0-D7给到12864,赋值这边怎么尝试都报错要不然就是参数没进去,没点亮,想请教各位大佬应该如何写?谢谢-QQ20240804-230628.png

这边在网上找了很多,尝试了很多方式想设定ODR寄存器后写入,但均为成功。QQ20240804-230656.png

下图是写命令和写数据,Debug显示DATA总是没有数据😕 QQ20240804-230705.png

附一下代码原档,希望得到各位大佬的指点~谢谢

QQ20240804-230628.png
QQ20240804-230656.png
QQ20240804-230705.png
收藏 评论6 发布时间:2024-8-4 23:16

举报

6个回答
龙龍 回答时间:2024-8-4 23:26:27

自己顶一下,好像发送不了ZIP和附件~没代码应该也没关系吧,应该也够了吧。囧

龙龍 回答时间:2024-8-4 23:34:27

LCDST7565P.c

include "stm32f1xx_hal.h"

include "gpio.h"

include "LCDST7565P.h"

include "ziku.h"

//以下部分在gpio.C文件中已完成初始化,这边可能冲突,不做定义 //void LCD12864_UserConfig(void){

// GPIO_InitTypeDef GPIO_InitStructure; //定义结构体

// __HAL_RCC_GPIOB_CLK_ENABLE();//使能 GPIOB 时钟。

// GPIO_InitStructure.Pin = LCD_DATA_PIN ; //配置引脚 数据部分 // GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; //定义输出速率为高速 // GPIO_InitStructure.Mode =GPIO_MODE_OUTPUT_PP;//设置数据输出为推挽输出 // HAL_GPIO_Init(LCD_DATA_PROT,&GPIO_InitStructure);//对上述进行初始化。

// GPIO_InitStructure.Pin = RS | RD | WR ; //配置引脚 数据部分 // GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; //定义输出速率为高速 // GPIO_InitStructure.Mode =GPIO_MODE_OUTPUT_PP;//设置数据输出为推挽输出 // HAL_GPIO_Init(LCD_CMD_PROT,&GPIO_InitStructure);//对上述进行初始化。

//} uint16_t temp; //写命令至12864 void LCD12864_write_cmd(uint16_t CMD){

    CS_LOW;
    RD_HIGH;
    RS_LOW;
    WR_LOW;
HAL_Delay(2);
 LCD_DATA_PIN(CMD);

// HAL_GPIO_WritePin(GPIOB, D0_Pin|D1_Pin|D2_Pin|D3_Pin|D4_Pin|D5_Pin|D6_Pin|D7_Pin,CMD); HAL_Delay(2); WR_HIGH; }

//写数据至12864 void LCD12864_write_data(uint16_t data){

    CS_LOW;
    RD_HIGH;
    RS_HIGH;
    WR_LOW;
HAL_Delay(2);
    LCD_DATA_PIN(data);

// HAL_GPIO_WritePin(GPIOB, D0_Pin|D1_Pin|D2_Pin|D3_Pin|D4_Pin|D5_Pin|D6_Pin|D7_Pin,data); HAL_Delay(2); WR_HIGH;

} //初始化12864 void LCD12864_Init(){

    CS_LOW;
    REST_LOW;
    HAL_Delay(1);
    REST_HIGH;

    LCD12864_write_cmd(0xE2);
    HAL_Delay(1);

    LCD12864_write_cmd(0xAF);
    HAL_Delay(1);

    LCD12864_write_cmd(0xC8);

    LCD12864_write_cmd(0x2F);
    HAL_Delay(1);

    LCD12864_write_cmd(0x25);

    LCD12864_write_cmd(0x81);
    LCD12864_write_cmd(0x25);

}

//清屏12864 void LCD12864_ClearScreen(void){

unsigned char i, j;

for (i=0; i<8; i++){
        LCD12864_write_cmd(0xB0+i);
        LCD12864_write_cmd(0x10);
        LCD12864_write_cmd(0x00);
     for (j=0; j<128; j++){
        LCD12864_write_data(0x00);
     }
}  

}

/***

  • 函 数 名 : LCD12864_Write16CnCHAR
  • 函数功能 : 在12864上面书写16X16的汉字
  • 输 入 : Page, Column, cn ***/

ifdef CHAR_CODE

extern "C" {

endif

unsigned char Lcd12864_Write16CnCHAR(unsigned char Page, unsigned char Column, char *cn) { unsigned char j, x1, x2, wordNum;

if(Page > 7) return 0; //页坐标只能从0到7,大于则直接返回 if(Column > 128) return 0; //列的坐标只能从0到127,大于则直接返回 Page += 0xB0; //求取页坐标的值 不能放在while里面

while ( *cn != '\0') //在C语言中字符串结束以‘\0’结尾 { LCD12864_write_cmd(Page); //设置页坐标

x1 = (Column >> 4)& 0x0F;       //先取出高4位  注释1
x2 = Column & 0x0F;             //取低四位 
LCD12864_write_cmd(0x10 + x1);  //设置列坐标 高4
LCD12864_write_cmd(0x00 + x2);  //           低4

for (wordNum=0; wordNum<8; wordNum++)
{
    //--查询要写的字在字库中的位置--//
    if ((CN16CHAR[wordNum].Index[0] == *cn) && (CN16CHAR[wordNum].Index[1] == *(cn+1)))
    {
        for (j=0; j<32; j++) //写一个字
        {
            if (j == 16) //16X16用到两个页坐标,当大于等于16时,切换页坐标
            {
            LCD12864_write_cmd(Page + 1);    //设置页坐标
                LCD12864_write_cmd(0x10 + x1);   //高4位 设置列坐标
                LCD12864_write_cmd(0x00 + x2);   //低4位
            }
            LCD12864_write_data(CN16CHAR[wordNum].Msk[j]);
        }
        Column += 16; //下一个字的新的列地址
        break;  //我们理解:一旦字库中找到字符,余下字库不用再找
    }  
} 
cn += 2;

} return 1; }

ifdef CHAR_CODE

}

endif


LCDST7565P.h

ifndef _LCDST7565PH

define _LCDST7565PH

include "stm32f1xx_hal.h"

include "gpio.h"

// GPIO_SETLOWBITS(GPIOB,UINT8) / GPIOB->ODR =/ ((GPIOB->ODR)&0x3F90) + UINT8 方式一失败 //#define LCD_DATA_PIN GPIOB->ODR = 0x3F90 //方式二失败

define LCD_DATA_PIN(newdata); GPIOB->ODR =newdata //GPIOB->ODR = GPIOB->ODR & 0x23F8 | newdata; //方式三

// 设置十六进制C8T6上设置PB3&D0\PB4&D1\PB5&D2\PB6&D3\PB7&D4\PB8&D5\PB9&D6\PB12&D7 //十六进制为0011 1111 1001 0000 注意,如果出现显示不正常现象,低位先进,则设置0x09F3 // #define LCD_DATA_PROT GPIOB //设置GPIOB为数据DATA

//以下部分在gpio.C文件中已完成宏定义,这边可能冲突,不做定义 //#define RS RS_Pin //数据指令选择 高电平数据 低电平指令 //#define RD RD_Pin //读使能 低电平有效 //#define WR WR_Pin //写使能 低电平有效 //#define LCD_CMD_PROT GPIOB //该分组为GPIOB?

//#define REST REST_Pin //复位 低电平有效 //#define LCD_REST_PROT GPIOC

//#define CS CS_Pin //片选 低电平有效 //#define LCD_CS_PROT GPIOA

//宏定义,设置各个控制脚,简化代码长度

define CS_LOW HAL_GPIO_WritePin (GPIOA,CS_Pin,GPIO_PIN_RESET);

define CS_HIGH HAL_GPIO_WritePin (GPIOA,CS_Pin,GPIO_PIN_SET);

define RS_LOW HAL_GPIO_WritePin (GPIOB,RS_Pin,GPIO_PIN_RESET);

define RS_HIGH HAL_GPIO_WritePin (GPIOB,RS_Pin,GPIO_PIN_SET);

define RD_LOW HAL_GPIO_WritePin (GPIOB,RD_Pin,GPIO_PIN_RESET);

define RD_HIGH HAL_GPIO_WritePin (GPIOB,RD_Pin,GPIO_PIN_SET);

define WR_LOW HAL_GPIO_WritePin (GPIOB,WR_Pin,GPIO_PIN_RESET);

define WR_HIGH HAL_GPIO_WritePin (GPIOB,WR_Pin,GPIO_PIN_SET);

define REST_LOW HAL_GPIO_WritePin (GPIOC,REST_Pin,GPIO_PIN_RESET);

define REST_HIGH HAL_GPIO_WritePin (GPIOC,REST_Pin,GPIO_PIN_SET);

//void LCD12864_UserConfig(void); void LCD12864_write_cmd(uint16_t CMD); void LCD12864_write_data(uint16_t data); void LCD12864_Init(void); void LCD12864_ClearScreen(void); unsigned char Lcd12864_Write16CnCHAR(unsigned char Page, unsigned char Column, char *cn);

endif


ziku.h

ifndef __CHARCODE_H

define __CHARCODE_H

ifdef CHAR_CODE

extern "C" {

endif

// ------------------ 汉字字模的数据结构定义 ------------------------ // struct Cn16CharTypeDef // 汉字字模数据结构 { unsigned char Index[2]; // 汉字内码索引,一个汉字占两个字节 unsigned char Msk[32]; // 点阵码数据(16*16有32个数据) };

//struct Cn16CharTypeDef code CN16CHAR[]=

struct Cn16CharTypeDef CN16CHAR[] = {

/-- 文字: 液 --/ /-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --/ "液",0x10,0x60,0x02,0x8C,0x00,0x84,0xE4,0x1C,0x05,0xC6,0xBC,0x24,0x24,0xE4,0x04,0x00, 0x04,0x04,0x7E,0x01,0x00,0x00,0xFF,0x82,0x41,0x26,0x18,0x29,0x46,0x81,0x80,0x00,

/-- 文字: 晶 --/ /-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --/ "晶",0x00,0x00,0x00,0x00,0x7F,0x49,0x49,0x49,0x49,0x49,0x7F,0x00,0x00,0x00,0x00,0x00, 0x00,0xFF,0x49,0x49,0x49,0x49,0xFF,0x00,0xFF,0x49,0x49,0x49,0x49,0xFF,0x00,0x00,

/-- 文字: 显 --/ /-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --/ "显",0x00,0x00,0x00,0xFE,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00,0x00, 0x40,0x42,0x44,0x58,0x40,0x7F,0x40,0x40,0x40,0x7F,0x40,0x50,0x48,0x46,0x40,0x00,

/-- 文字: 示 --/ /-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --/ "示",0x40,0x40,0x42,0x42,0x42,0x42,0x42,0xC2,0x42,0x42,0x42,0x42,0x42,0x40,0x40,0x00, 0x20,0x10,0x08,0x06,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x02,0x04,0x08,0x30,0x00,

/-- 文字: 文 --/ /-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --/ "文",0x08,0x08,0x08,0x38,0xC8,0x08,0x09,0x0E,0x08,0x08,0xC8,0x38,0x08,0x08,0x08,0x00, 0x80,0x80,0x40,0x40,0x20,0x11,0x0A,0x04,0x0A,0x11,0x20,0x40,0x40,0x80,0x80,0x00,

/-- 文字: 字 --/ /-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --/ "字",0x10,0x0C,0x04,0x24,0x24,0x24,0x25,0x26,0xA4,0x64,0x24,0x04,0x04,0x14,0x0C,0x00, 0x02,0x02,0x02,0x02,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,

/-- 文字: 测 --/ /-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --/ "测",0x10,0x60,0x02,0x8C,0x00,0xFE,0x02,0xF2,0x02,0xFE,0x00,0xF8,0x00,0xFF,0x00,0x00, 0x04,0x04,0x7E,0x01,0x80,0x47,0x30,0x0F,0x10,0x27,0x00,0x47,0x80,0x7F,0x00,0x00,

/-- 文字: 试 --/ /-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --/ "试",0x40,0x40,0x42,0xCC,0x00,0x90,0x90,0x90,0x90,0x90,0xFF,0x10,0x11,0x16,0x10,0x00, 0x00,0x00,0x00,0x3F,0x10,0x28,0x60,0x3F,0x10,0x10,0x01,0x0E,0x30,0x40,0xF0,0x00,

};

endif //end of CHAR_CODE

ifdef CHAR_CODE

}

endif


main.c 主函数部分

int main(void) { / USER CODE BEGIN 1 /

/ USER CODE END 1 /

/ MCU Configuration--------------------------------------------------------/

/ Reset of all peripherals, Initializes the Flash interface and the Systick. / HAL_Init();

/ USER CODE BEGIN Init /

/ USER CODE END Init /

/ Configure the system clock / SystemClock_Config();

/ USER CODE BEGIN SysInit /

/ USER CODE END SysInit /

/ Initialize all configured peripherals / MX_GPIO_Init(); MX_ADC1_Init(); MX_I2C2_Init(); MX_SPI1_Init(); / USER CODE BEGIN 2 /

__HAL_RCC_GPIOB_CLK_ENABLE();

// unsigned char i;

LCD12864_Init();

LCD12864_ClearScreen(); / USER CODE END 2 /

/ Infinite loop / / USER CODE BEGIN WHILE / while (1) { / USER CODE END WHILE /

/ USER CODE BEGIN 3 / LCD12864_ClearScreen(); // 页地址 列地址 显示文字 Lcd12864_Write16CnCHAR(0, 0, "液晶显示文字测试"); Lcd12864_Write16CnCHAR(2, 0, "试测字文示显晶液"); Lcd12864_Write16CnCHAR(4, 0, "显示文字测试液晶"); Lcd12864_Write16CnCHAR(6, 0, "文字显示液晶测试"); HAL_Delay(200); //不能删除,如删除会出现文字清屏不彻底导致留尾巴

//效果  :四行动态显示"液晶显示文字测试"八个字

// for (i=0; i<8; i += 2) // { // LCD12864_ClearScreen(); // Lcd12864_Write16CnCHAR(i, 0, "液晶显示文字测试"); // HAL_Delay(200); // }

} / USER CODE END 3 /

}

xmshao 回答时间:2024-8-5 10:01:50
感觉你的问题未必出在这个写操作上,你是说现在的数据跨了多个IO PORT,但你的LCD控制器是有片选的,在取消选中时,
你基于位操作一位位写来准备数据,也不用多少时间,写完后使能片选。你结合LCD的控制时序图看看。
butterflyspring 回答时间:2024-8-5 11:50:24
通常通讯传递数据,会在特定时间内给出新数据,这个时间内数据变化是不影响或不被接收的。

所以同时给数据是个相对概念,按照这个连线,无非数据准备时间长一点点,即使分布在同一口上,也就快了几个指令周期而已。

所以很有可能是控制逻辑出了问题,最好再看看规格书。
龙龍 回答时间:2024-8-5 22:01:50

xmshao 发表于 2024-8-5 10:01
感觉你的问题未必出在这个写操作上,你是说现在的数据跨了多个IO PORT,但你的LCD控制器是有片选的,在取消 ...

感谢,但是我排查了电路,用示波器检测,发现其他端口均正常,就D7这个PIN的输出速率和电平不正常,然后在代码分析里面检测了DATA这个值,发现一直为0,所以觉得是数据没有写进去,代码是根据51移植的,所以感觉很大可能是赋值操作,,,,我再继续排查吧~

龙龍 回答时间:2024-8-5 22:04:48

butterflyspring 发表于 2024-8-5 11:50
通常通讯传递数据,会在特定时间内给出新数据,这个时间内数据变化是不影响或不被接收的。</p>
<p>所以同时给数据 ...

谢谢,代码是51单片机移植过来的,控制逻辑上感觉应该是没有太大问题,用示波器检测发现电平端口也正常,后在程序内检测DATA值一直为0,结合示波器D7端口的异常现象,觉得是值没有写到LCD内导致....

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版