发新帖

[ST] STM32F407VE单片机使用I2C接口操作FYD12864-1001A液晶

admin 2月前 199


【接线】

上面:GND, VCC=5V, CS=高电平, SDA=PB7, SCK=PB6, RST=PA1

下面:WR=RD=DB2=DB4=DB5=GND(可自定义), DB6=GND, D/C=高电平

其余引脚悬空!

DB3必须悬空!因为在电路板上DB3是和CS相连的,且CS接的是高电平,所以该位地址始终为1,不能修改

特别注意,D/C必须要接高电平(3V或5V均可),否则有时上电后屏幕无法显示文字!

I2C_ADDR  7  6       5     4        3        2   1       0

引脚              0  WR  RD  DB5  DB4  1   DB2  0

最终地址      0  0      0      0        0       1    0       0       ->      0x04

地址引脚上的电平改变后,I2C地址立即改变。

【跳线配置】

用焊锡短接JPS, JP4B, JP68, JPSCS, JPS3L

断开以下跳线:JPS3H, JP80, JPP, JP8B

JP8B是默认焊接上的,选I2C模式时必须断开该跳线,否则上电就会发生短路!

JPA和JPK跳线决定背光是否使用与模块相同的电源。

判断某个引脚是否为悬空状态的方法:

将万用表调到测电压模式,将表笔

1. 将表笔连到GND与被测引脚之间,0V

2. 将表笔连到VCC与被测引脚之间,0V

3. 重新连到GND与被测引脚之间,示数为2.3V

则证明该引脚为悬空状态。

如果被测引脚与GND或VCC之间的电压始终固定,则表明引脚不为悬空状态,不可以用杜邦线直接连到VCC或GND,否则有短路的危险。

DB3在电路板上是和CS引脚连通的,由于选I2C模式时CS必须为高电平,所以DB3固定为高电平,不可外接杜邦线。

DB6=DB7=0时液晶屏使用I2C模式,由于DB7在液晶背面有JPS3L跳线,所以可悬空。DB6与JPS3H跳线相连,JPS3H短接时DB6为高电平,不是I2C模式,所以不能短接JPS3H,并且要用杜邦线把DB6接到GND。

该液晶使用的控制芯片是RA8816,在网上很容易搜索到datasheet。

【测试程序】

main.c:

#include <stdio.h>  
#include <stm32f4xx.h>  
#include "FYD12864.h"  
  
#define FYD12864 ((FILE *)3)  
  
void delay(uint16_t nms)  
{  
  TIM_TimeBaseInitTypeDef tim;  
  TIM_SelectOnePulseMode(TIM6, TIM_OPMode_Single);  
  TIM_UpdateRequestConfig(TIM6, TIM_UpdateSource_Regular);  
    
  tim.TIM_ClockDivision = TIM_CKD_DIV1;  
  tim.TIM_CounterMode = TIM_CounterMode_Up;  
  tim.TIM_Period = 10 * nms - 1;  
  tim.TIM_Prescaler = 8399;  
  TIM_TimeBaseInit(TIM6, &tim);  
  TIM_Cmd(TIM6, ENABLE);  
    
  while (TIM_GetFlagStatus(TIM6, TIM_FLAG_Update) == RESET);  
  TIM_ClearFlag(TIM6, TIM_FLAG_Update);  
}  
  
int fputc(int ch, FILE *fp)  
{  
  if (fp == stdout)  
  {  
    if (ch == '\n')  
    {  
      while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);  
      USART_SendData(USART1, '\r');  
    }  
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);  
    USART_SendData(USART1, ch);  
  }  
  else if (fp == FYD12864)  
  {  
    if (ch == '\n')  
      FYD12864_NewLine();  
    else  
      FYD12864_Write(FYD12864_RAMD, ch);  
  }  
  return ch;  
}  
  
void show_clock(void)  
{  
  RCC_ClocksTypeDef clocks;  
  RCC_GetClocksFreq(&clocks);  
  printf("STM32F407VE\n");  
  printf("SYSCLK=%.2fMHz HCLK=%.2fMHz PCLK1=%.2fMHz PCLK2=%.2fMHz\n", clocks.SYSCLK_Frequency / 1000000.0, clocks.HCLK_Frequency / 1000000.0, clocks.PCLK1_Frequency / 1000000.0, clocks.PCLK2_Frequency / 1000000.0);  
}  
  
// 显示I2C有应答的从器件地址  
uint8_t get_i2c_addr(void)  
{  
  uint8_t addr;  
  uint8_t acked = 0;  
  for (addr = 0x02; addr <= 0xfc; addr += 2)  
  {  
    I2C_GenerateSTART(I2C1, ENABLE);  
    while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);  
    I2C_Send7bitAddress(I2C1, addr, I2C_Direction_Transmitter);  
    while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR && I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == RESET);  
    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == RESET)  
    {  
      acked = addr;  
      printf("0x%02x: ACK\n", addr);  
    }  
    else  
    {  
      I2C_ClearFlag(I2C1, I2C_FLAG_AF);  
      //printf("0x%02x: NACK\n", addr);  
    }  
    I2C_GenerateSTOP(I2C1, ENABLE);  
    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);  
  }  
  if (acked == 0)  
    printf("No slave!\n");  
  return acked;  
}  
  
int main(void)  
{  
  GPIO_InitTypeDef gpio;  
  I2C_InitTypeDef i2c;  
  USART_InitTypeDef usart;  
    
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE);  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 | RCC_APB1Periph_TIM6, ENABLE);  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);  
    
  gpio.GPIO_Mode = GPIO_Mode_OUT;  
  gpio.GPIO_OType = GPIO_OType_PP;  
  gpio.GPIO_Pin = GPIO_Pin_1;  
  gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;  
  gpio.GPIO_Speed = GPIO_Low_Speed;  
  GPIO_Init(GPIOA, &gpio);  
    
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);  
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);  
  gpio.GPIO_Mode = GPIO_Mode_AF;  
  gpio.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;  
  gpio.GPIO_Speed = GPIO_High_Speed;  
  GPIO_Init(GPIOA, &gpio);  
    
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);  
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);  
  gpio.GPIO_OType = GPIO_OType_OD;  
  gpio.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;  
  gpio.GPIO_PuPd = GPIO_PuPd_UP;  
  GPIO_Init(GPIOB, &gpio);  
    
  usart.USART_BaudRate = 115200;  
  usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
  usart.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;  
  usart.USART_Parity = USART_Parity_No;  
  usart.USART_StopBits = USART_StopBits_1;  
  usart.USART_WordLength = USART_WordLength_8b;  
  USART_Init(USART1, &usart);  
  USART_Cmd(USART1, ENABLE);  
    
  i2c.I2C_Ack = I2C_Ack_Disable;  
  i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;  
  i2c.I2C_ClockSpeed = 10000; // 速度不能太快, 否则会乱码  
  i2c.I2C_DutyCycle = I2C_DutyCycle_2;  
  i2c.I2C_Mode = I2C_Mode_I2C;  
  i2c.I2C_OwnAddress1 = 0;  
  I2C_Init(I2C1, &i2c);  
  I2C_Cmd(I2C1, ENABLE);  
    
  show_clock();  
  //get_i2c_addr();  
    
  FYD12864_Init();  
  FYD12864_WriteString("STM32F407VE型号"); // I2C方式批量写入, 不支持\n  
  FYD12864_NewLine(); // 换行  
  FYD12864_WriteString("意法半导体单片机");  
  fprintf(FYD12864, "微控制器\n波特率:%d", usart.USART_BaudRate); // I2C一个一个字符写入, 支持\n  
  while (1)  
    __WFI();  
}


FYD12864.h:

#define FYD12864_ADDR 0x04  
  
#define FYD12864_DWFR 0x00  
  
#define FYD12864_PWRR 0x01  
#define FYD12864_PWRR_SRST 0x80  
#define FYD12864_PWRR_MCLR 0x40  
#define FYD12864_PWRR_DOFF_Z 0x02  
  
#define FYD12864_SYSR 0x02  
#define FYD12864_SYSR_LS 0xf0  
#define FYD12864_SYSR_LS_Pos 4  
#define FYD12864_SYSR_GB_EN 0x08  
#define FYD12864_SYSR_RS 0x03  
#define FYD12864_SYSR_RS_Pos 0  
  
#define FYD12864_MWMR 0x03  
#define FYD12864_MWMR_MD 0x03  
#define FYD12864_MWMR_MD_Pos 0  
  
#define FYD12864_XCUR 0x05  
#define FYD12864_XCUR_X 0x3f  
#define FYD12864_YCUR 0x06  
#define FYD12864_YCUR_Y 0x7f  
  
#define FYD12864_ISR 0x0f // Interrupt Status  
#define FYD12864_ISR_BF 0x80 // Busy Flag  
#define FYD12864_ISR_IO_I 0x08 // I/O Port Interrupt  
#define FYD12864_ISR_SCR_I 0x04 // Scroll interrupt  
#define FYD12864_ISR_KI 0x02 // Key-scan interrupt  
#define FYD12864_ISR_BI 0x01 // Busy Interrupt  
  
#define FYD12864_CSTR 0x10 // Contrast Adjust Register  
#define FYD12864_CSTR_BR 0xe0 // Bias  
#define FYD12864_CSTR_BR_Pos 5  
#define FYD12864_CSTR_CT 0x1f // Contrast  
#define FYD12864_CSTR_CT_Pos 0  
  
#define FYD12864_DRCRA 0x11 // Driver Control Register1  
#define FYD12864_DRCRA_BOFF 0x80 // Booster control  
#define FYD12864_DRCRA_EN_R 0x40 // Reference voltage control  
#define FYD12864_DRCRA_EN_G 0x20 // V0 control  
#define FYD12864_DRCRA_ROFF 0x10 // Voltage Follower control  
#define FYD12864_DRCRA_IDIR 0x08 // Icon sequence select  
#define FYD12864_DRCRA_CDIR 0x02 // Common sequency select  
#define FYD12864_DRCRA_SDIR 0x01 // Segment sequency select  
  
#define FYD12864_DRCRB 0x12 // Driver Control Register2  
#define FYD12864_DRCRB_CK_BS 0xc0 // clock of Booster  
#define FYD12864_DRCRB_CK_BS_Pos 6  
#define FYD12864_DRCRB_RR 0x38 // Resistor Ratio of Regulator  
#define FYD12864_DRCRB_RR_Pos 3  
#define FYD12864_DRCRB_IRS 0x04 // resistors for the V0 voltage level adjustment  
#define FYD12864_DRCRB_HD 0x03 // LCD driving current  
#define FYD12864_DRCRB_HD_Pos 0  
  
#define FYD12864_RAMD 0x80 // Memory Data  
  
typedef enum {FYD12864_Mode_Image = 0, FYD12864_Mode_8x8 = 1, FYD12864_Mode_8x16 = 2, FYD12864_Mode_16x16 = 3} FYD12864_Mode;  
  
void FYD12864_Clear(void);  
void FYD12864_Init(void);  
void FYD12864_NewLine(void);  
uint8_t FYD12864_Read(uint8_t addr);  
void FYD12864_Reset(void);  
void FYD12864_SetMode(FYD12864_Mode mode);  
void FYD12864_SetPos(uint8_t x, uint8_t y);  
void FYD12864_Wait(void);  
uint8_t FYD12864_Write(uint8_t addr, uint8_t value);  
uint8_t FYD12864_WriteData(const void *data, uint8_t len);  
uint8_t FYD12864_WriteString(const char *str);


FYD12864.c:

#include <stdio.h>  
#include <stm32f4xx.h>  
#include <string.h>  
#include "FYD12864.h"  
  
void delay(uint16_t nms);  
  
void FYD12864_Clear(void)  
{  
  FYD12864_Write(FYD12864_PWRR, FYD12864_Read(FYD12864_PWRR) | FYD12864_PWRR_MCLR);  
  FYD12864_Wait();  
}  
  
void FYD12864_Init(void)  
{  
  FYD12864_Reset(); // 复位  
  FYD12864_Write(FYD12864_SYSR, (7 << FYD12864_SYSR_LS_Pos) | FYD12864_SYSR_GB_EN | FYD12864_SYSR_RS); // 128x64, GB Code  
  FYD12864_SetMode(FYD12864_Mode_16x16); // 16x16字型模式  
  FYD12864_Write(FYD12864_CSTR, (4 << FYD12864_CSTR_BR_Pos) | (23 << FYD12864_CSTR_CT_Pos)); // 设置对比度  
  FYD12864_Write(FYD12864_DRCRA, FYD12864_DRCRA_BOFF | FYD12864_DRCRA_EN_R | FYD12864_DRCRA_EN_G | FYD12864_DRCRA_ROFF);  
  FYD12864_Write(FYD12864_DRCRB, FYD12864_DRCRB_CK_BS | (6 << FYD12864_DRCRB_RR_Pos) | FYD12864_DRCRB_IRS | FYD12864_DRCRB_HD); // 12.5kHz, X6, 大电流  
  FYD12864_Write(FYD12864_PWRR, FYD12864_PWRR_DOFF_Z); // 打开显示功能  
  FYD12864_Clear(); // 清屏  
}  
  
// 换行  
void FYD12864_NewLine(void)  
{  
  FYD12864_SetPos(0, FYD12864_Read(FYD12864_YCUR) + 16);  
}  
  
uint8_t FYD12864_Read(uint8_t addr)  
{  
  I2C_GenerateSTART(I2C1, ENABLE);  
  while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);  
  I2C_Send7bitAddress(I2C1, FYD12864_ADDR, I2C_Direction_Transmitter);  
  while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR && I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == RESET);  
  if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == RESET)  
  {  
    I2C_SendData(I2C1, addr);  
    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);  
      
    I2C_GenerateSTART(I2C1, ENABLE);  
    while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);  
    I2C_Send7bitAddress(I2C1, FYD12864_ADDR, I2C_Direction_Receiver);  
    while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) == ERROR);  
      
    I2C_GenerateSTOP(I2C1, ENABLE);  
    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);  
    return I2C_ReceiveData(I2C1);  
  }  
  else  
  {  
    I2C_ClearFlag(I2C1, I2C_FLAG_AF);  
    I2C_GenerateSTOP(I2C1, ENABLE);  
    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);  
    printf("No ack!\n");  
    return 0;  
  }  
}  
  
void FYD12864_Reset(void)  
{  
  GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_RESET);  
  delay(30);  
  GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_SET);  
  delay(150);  
}  
  
void FYD12864_SetMode(FYD12864_Mode mode)  
{  
  FYD12864_Write(FYD12864_MWMR, (FYD12864_Read(FYD12864_MWMR) & ~FYD12864_MWMR_MD) | (mode << FYD12864_MWMR_MD_Pos));  
}  
  
void FYD12864_SetPos(uint8_t x, uint8_t y)  
{  
  FYD12864_Write(FYD12864_XCUR, x & FYD12864_XCUR_X);  
  FYD12864_Write(FYD12864_YCUR, y & FYD12864_YCUR_Y);  
}  
  
void FYD12864_Wait(void)  
{  
  while (FYD12864_Read(FYD12864_ISR) & FYD12864_ISR_BF);  
}  
  
uint8_t FYD12864_Write(uint8_t addr, uint8_t value)  
{  
  uint8_t ret = 0;  
  I2C_GenerateSTART(I2C1, ENABLE);  
  while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);  
  I2C_Send7bitAddress(I2C1, FYD12864_ADDR, I2C_Direction_Transmitter);  
  while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR && I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == RESET);  
  if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == RESET)  
  {  
    ret = 1;  
    I2C_SendData(I2C1, addr);  
    I2C_SendData(I2C1, value);  
    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);  
  }  
  else  
  {  
    I2C_ClearFlag(I2C1, I2C_FLAG_AF);  
    printf("No ack!\n");  
  }  
  I2C_GenerateSTOP(I2C1, ENABLE);  
  while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);  
  return ret;  
}  
  
// 此函数没有对AF, ARLO, BERR等错误进行处理, 所以请不要在短时间内发送大量的数据!  
uint8_t FYD12864_WriteData(const void *data, uint8_t len)  
{  
  const uint8_t *p = data;  
  uint8_t ret = 0;  
    
  I2C_GenerateSTART(I2C1, ENABLE);  
  while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);  
  I2C_Send7bitAddress(I2C1, FYD12864_ADDR, I2C_Direction_Transmitter);  
  while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR && I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == RESET);  
  if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == RESET)  
  {  
    ret = 1;  
    I2C_SendData(I2C1, FYD12864_RAMD);  
    while (len--)  
    {  
      while (I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) == RESET);  
      I2C_SendData(I2C1, *p++);  
    }  
    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);  
  }  
  else  
  {  
    I2C_ClearFlag(I2C1, I2C_FLAG_AF);  
    printf("No ack!\n");  
  }  
  I2C_GenerateSTOP(I2C1, ENABLE);  
  while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);  
  return ret;  
}  
  
uint8_t FYD12864_WriteString(const char *str)  
{  
  return FYD12864_WriteData(str, strlen(str));  
}

上电时屏幕不显示内容,按下STM32复位键后才能显示的解决办法:

确保D/C引脚已接到高电平。断开JPA跳线,JA引脚接9012三极管的集电极,基极通过一个10kΩ的电阻接到单片机PB7端口上,发射极接+5V。通电时先暂不打开背光,等初始化完毕了再开背光,PB7设为开漏输出模式,PB7=0时点亮背光。

// STM32F103ZE单片机  
// int main(void):  
GPIO_WriteBit(GPIOB, GPIO_Pin_7, Bit_SET); // 关背光  
gpio.GPIO_Mode = GPIO_Mode_Out_OD;  
gpio.GPIO_Pin = GPIO_Pin_7;  
gpio.GPIO_Speed = GPIO_Speed_2MHz;  
GPIO_Init(GPIOB, &gpio);  
  
void FYD12864_Init(void)  
{  
  FYD12864_Reset(); // 复位  
  FYD12864_Write(FYD12864_SYSR, (7 << FYD12864_SYSR_LS_Pos) | FYD12864_SYSR_GB_EN | FYD12864_SYSR_RS); // 128x64, GB Code  
  FYD12864_SetMode(FYD12864_Mode_16x16); // 16x16字型模式  
  FYD12864_Write(FYD12864_CSTR, (4 << FYD12864_CSTR_BR_Pos) | (23 << FYD12864_CSTR_CT_Pos)); // 设置对比度  
  FYD12864_Write(FYD12864_DRCRA, FYD12864_DRCRA_BOFF | FYD12864_DRCRA_EN_R | FYD12864_DRCRA_EN_G | FYD12864_DRCRA_ROFF);  
  FYD12864_Write(FYD12864_DRCRB, FYD12864_DRCRB_CK_BS | (6 << FYD12864_DRCRB_RR_Pos) | FYD12864_DRCRB_IRS | FYD12864_DRCRB_HD); // 12.5kHz, X6, 大电流  
  FYD12864_Write(FYD12864_PWRR, FYD12864_PWRR_DOFF_Z); // 打开显示功能  
  FYD12864_Clear(); // 清屏  
  GPIO_WriteBit(GPIOB, GPIO_Pin_7, Bit_RESET); // 开背光  
}

经测试,问题完美解决:

5秒后自动熄灭背光,单片机进入STOP模式:

最新回复 (0)
返回