GD32E230C8T6《调试篇》之 FMC(闪存)的读写 + USART打印

本文详细描述了一项基于GD32E230C8T6微控制器的实验,涉及GPIO配置、USART通信、I2C与数码管交互、按键扫描以及Flash存储操作,展示了如何利用这些功能进行数据读写和显示控制。
摘要由CSDN通过智能技术生成

实验:按键DIG4(保存键),任意按下一个数字后,再按保存键写入flash;断电后重新上电,从 flash里读值,显示到数码管

实验工具

	主芯片GD32E230C8T6 /4段8位数码管/GN1650驱动芯片(IIC通讯)/USART/485通讯芯片

GD32E230C8T6

在这里插入图片描述
在这里插入图片描述

查看GPIO

在这里插入图片描述

在这里插入图片描述

查看Datasheet 2.6.7章节GPIO 复用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
说明使用PA9、 PA10的USART0时要选择AF1;
初始化USART0 时才有了这两句;
与GD32E103不同的是E230没有gpio_init这个库函数,所以参考例程是有帮助的;

    /* connect port to USARTx_Tx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);
    /* connect port to USARTx_Rx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10);

查看用户手册

可以看到E230有64K的主flash,这里我选了0x0800 FC00,操作最后一页;
在这里插入图片描述

代码

main.h


//IIC所有操作函数
void i2c_init(void);  //初始化IIC的IO口	
static void IIC_Start1(void); 
static void IIC_Stop1(void);
uint8_t IIC_Rev_Byte(void);  //对IIC数据进行读出
void IIC_Wrt_Byte(uint8_t data);		//IIC发送一个字节
void IIC_ACK(void);						//IIC发送信号
void IIC_NAck(void);					//IIC不发送ACK信号
void SDA_Rx(void);						//主机recv from 从机
/************** GN1650 **************/
void GN1650_display(void);				//数码管显示
void  GN1650_display_D(void);			//数码管无显示
void GN1650_Wrt_RAM(uint8_t Address, uint8_t Data);  //对IIC数据进行写入

uint8_t GetKey(void);					//按键扫描
/************** usart ************/
void usart0_init();	
/************** flash ************/
uint8_t FMC_FLASH_Write( u32 data );
uint8_t FMC_FLASH_Read(u32 *data );

main.c

#define READ_SDA gpio_input_bit_get(GPIOB,GPIO_PIN_7)
#define LEDDOT 0x80
#define MAXNUM  10

#define TIMEPRESS  350 //key press times
#define DIG1 17
#define DIG2 25
#define DIG3 21
#define DIG4 29
#define ADDRMAX 512
uint8_t i;

uint16_t value=0;
		
void myGPIO_init(void)
{
	 /* enable GPIOB clock */
	 rcu_periph_clock_enable(RCU_GPIOA);	
		
	 gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ,GPIO_PIN_0);//PB6_42  I2C0_SCL GPIO_OTYPE_PP推挽输出
	 gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_0);	
}

void keycheck(void)
{
	uint16_t KeyNum;
	uint16_t LastKeyNum = 0;
	static uint8_t Keyleased=1,fastCnt=0;
	static uint16_t keydowntime = 0;
	
	KeyNum = GetKey();
	switch(KeyNum)
	{
		case DIG2:
			
			if(keydowntime++ >= TIMEPRESS )//long press ++
			{
				keydowntime=TIMEPRESS;
				if(++fastCnt>=10)//add press times 分频
				{
					fastCnt=0;
					value++;
					if(value > ADDRMAX) value = 1;  //512 to 1
				}				
			}
			else if(Keyleased && keydowntime < TIMEPRESS )//short press ++
			{
				value++;	
				Keyleased = 0;
				if(value > ADDRMAX) value = 1;    //512 to 1
			}							
			break;	
		
		case DIG3:	
			
			if( keydowntime++ >= TIMEPRESS)//long press --
			{	
				keydowntime=TIMEPRESS;
				if(++fastCnt>=10)//add press times 分频
				{
					fastCnt=0;
					value--;
					if(value == 0) value = ADDRMAX;   //0 to 512
				}								
			}
			else if(Keyleased  && keydowntime++ < TIMEPRESS )//short press --
			{
				value--;
				Keyleased=0; //keydown locked	
				if(value == 0) value = ADDRMAX;   //0 to 512
			}
							
			break;
			
		case DIG4:
			if(Keyleased)
			{			
				FMC_FLASH_Write(value);
		
				printf("****value=%d****\r\n",value);
				
				Keyleased = 0;
			}
			break;
			
		default:
			
			Keyleased=1;//keydown loosed
		
			fastCnt=0;

			keydowntime = 0;
			//lontimeflag = 1;
			break;
	}
}

//主函数处理
int main(void)
{
	uint8_t flag = 0;
	
	systick_config();
	
	delay_ms(10);
	
	usart0_init();
		
	//myGPIO_init();
	
	delay_ms(10);
 	
	i2c_init();
	
	FMC_FLASH_Read((u32 *)&value);//read flash	

    while(1)
	{
		flag =!flag;
		gpio_bit_write(GPIOA,GPIO_PIN_0,flag);
		delay_ms(1);
		
		keycheck();
		
		GN1650_display();		
					
		//do work1
		
		//do work2				
	}
 
}
/********** 数码管显示 **********/
void  GN1650_display(void)	
{		
	GN1650_Wrt_RAM(0x68,LEDENCODE[value/1000%10]);//high //0x48 系统指令  0x41//4级亮度 8段显示 显示开
	GN1650_Wrt_RAM(0x6A,LEDENCODE[value/100%10] );//   ;
	GN1650_Wrt_RAM(0x6C,LEDENCODE[value/10%10]);
	GN1650_Wrt_RAM(0x6E,LEDENCODE[value%10] ); //low
	
	GN1650_Wrt_RAM(0x48,0x01);
	
}
/********** 数码管无显示 **********/
void  GN1650_display_D(void)	
{
	GN1650_Wrt_RAM(0x48,0x00);
}
/**********  IIC初始化 *********/
void i2c_init(void)
{
	 /* enable GPIOB clock */
	 rcu_periph_clock_enable(RCU_GPIOB);
	 /* enable I2C0 clock */
	 rcu_periph_clock_enable(RCU_I2C0);
	
	 /* connect PB6 to I2C0_SCL */
	 gpio_af_set(GPIOB,GPIO_AF_1,GPIO_PIN_6);
	 /* connect PB7 to I2C0_SDA */
	 gpio_af_set(GPIOB,GPIO_AF_1,GPIO_PIN_7);
	
	 gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ,GPIO_PIN_6);//PB6_42  I2C0_SCL 
	 gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_6);
	
	 gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ,GPIO_PIN_7);//PB7_43  I2C0_SDA
	 gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_7);
			
	 /* configure I2C0 clock */
	 //i2c_clock_config(I2C0,60000,I2C_DTCY_2);

	 /* enable I2C0 */
	 i2c_enable(I2C0);
	 /* enable acknowledge */
	 i2c_ack_config(I2C0,I2C_I2CMODE_ENABLE);
	 
	 /*  空闲状态 */
	 gpio_bit_write(GPIOB,GPIO_PIN_6,1);
	 gpio_bit_write(GPIOB,GPIO_PIN_7,1);
	 
	 GN1650_Wrt_RAM(0x48,0x00);//关闭显示
	 	
}
void SDA_Rx(void)					//主机recv from 从机
{
	 /* enable GPIOB clock */
	 rcu_periph_clock_enable(RCU_GPIOB);
	 gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_7);
	
}
void SDA_Tx(void)
{
	 /* enable GPIOB clock */
	 rcu_periph_clock_enable(RCU_GPIOB);
	 gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ,GPIO_PIN_7);//PB7_43  I2C0_SDA
	 gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_7);
}

void IIC_SCL(uint8_t n)
{
	gpio_bit_write(GPIOB,GPIO_PIN_6,n);
}

void IIC_SDA(uint8_t n)
{
	gpio_bit_write(GPIOB,GPIO_PIN_7,n);
}


static void IIC_Delay(void)
{
	__IO  uint16_t cnt=1;
	while(cnt--);
}

/*********************模拟IIC通信****************/
/*
*函数功能:IIC起始
*提    示:
*输入参数:无
*输出参数:无
*返回值  :无
*/
static void IIC_Start1(void)
{
	SDA_Tx();
	//2、SCL 1
	IIC_SCL(1);
	//3、SDA 1
	IIC_SDA(1);
	//延时5us
	IIC_Delay();
	//4、SCL 0 
	IIC_SDA(0);
	//延时5us
	IIC_Delay();
	//5、SDA 0
	IIC_SCL(0);
	//延时5us
	IIC_Delay();		
}


/*
*函数功能:IIC结束
*提    示:
*输入参数:无
*输出参数:无
*返回值  :无
*/

static void IIC_Stop1(void)
{
	//2、SCL 1
	IIC_SCL(1);
	//3、SDA 0
	IIC_SDA(0);
	//延时5us
	IIC_Delay();
	//4、SDA 1
	IIC_SDA(1);
	//延时5us
	IIC_Delay();
}

/*
*函数功能:IIC应答
*提    示:
*输入参数:无
*输出参数:无
*返回值  :无
*/
void IIC_ACK(void)
{	
	SDA_Rx();
	IIC_SCL(0);
	IIC_Delay(); 
	IIC_SDA(0); 	
	IIC_Delay();     
	IIC_SCL(1);
	IIC_Delay();                  
	IIC_SCL(0);                     
	IIC_Delay();
	SDA_Tx(); 
	IIC_SDA(0);	
	IIC_Delay();
		
}


/****************模拟IIC通信**************/

/* 描述:一个字节数据发送函数               
 * 参数:  无
 * 返回值:无		*/

void IIC_Wrt_Byte(uint8_t data)
{
	int i;	
    IIC_SCL(0);    //拉低时钟开始数据传输
	for(i = 0;i < 8;i++)
	{
		IIC_SDA((data & 0x80)>0 ); //check bit7
        data <<= 1; 	  
		IIC_Delay();   //这三个延时都是必须的
		IIC_SCL(1);
		IIC_Delay(); 
		IIC_SCL(0);	
		IIC_Delay();	
	}	
}

/* 描述:一个字节数据接收函数               
 * 参数:  无
 * 返回值:接收到的字节数据		*/

uint8_t IIC_Rev_Byte(void)
{
	uint8_t dat=0;
	uint8_t i;	
 
	SDA_Rx();			/* 设置数据线为输入方式 */
	IIC_Delay();                    
	for(i = 0;i < 8;i++)
	{  
		IIC_SCL(0);		/* 设置时钟线为低,准备接收数据位	*/
		IIC_Delay();               
		IIC_SCL(1);		/* 设置时钟线为高使数据线上数据有效  */              
		if(READ_SDA) dat|=0x80;	//同ret++; /* 读数据位,接收的数据位放入ret中 */
		dat>>=1;
		IIC_Delay();
	}
	IIC_SCL(0); 
 	
	return dat;
}

// write to RAM
void GN1650_Wrt_RAM(uint8_t Address, uint8_t Data)
{
	IIC_Start1();
    IIC_Wrt_Byte(Address);
    IIC_ACK();
    IIC_Wrt_Byte(Data);
    IIC_ACK();
    IIC_Stop1();	
}
/********** get 4 按键 ID **********/
uint8_t GetKey(void)
{
	uint8_t key=0;
	
	IIC_Start1();
	IIC_Wrt_Byte(0x49);
	IIC_ACK();
	key= IIC_Rev_Byte();
	IIC_ACK();
	IIC_Stop1();
	return key;
}

#define  ADDRSTART 0x0800FC00
/****************** flash write **************/
/*!
    \brief      FLASH写
    @Address    操作地址
    @Size       数据长度
*/
uint8_t FMC_FLASH_Write(u32 data)
{
    fmc_state_enum FLASHStatus;
    uint16_t i;    
    uint32_t Address = ADDRSTART;
	
    /* 解锁 */
    fmc_unlock();
	/* step1: erase pages */
    fmc_page_erase(Address);
    /* step2: 操作FMC前先清空STAT 状态寄存器,非常必要*/
    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR );
    fmc_word_program(Address, data);
	fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR );
    /* 上锁 */
    fmc_lock();
    return 0;
}
/****************** flash read **************/

/*!
    \brief      FLASH读
    @Address    操作地址
    @data      数据指针
*/
uint8_t FMC_FLASH_Read(u32 *data)
{
    uint32_t Address = ADDRSTART;
 
    *data = *( __IO uint32_t* ) Address;
	
    return 0;

}

/****************** usart0 print **************/

void usart0_init() // 初始化串口0
{
	/* enable COM GPIO clock */
	rcu_periph_clock_enable(RCU_GPIOA);  // 使能GPIOA时钟
	rcu_periph_clock_enable(RCU_GPIOB);  // 使能GPIOB时钟
	rcu_usart_clock_config(CK_APB2);
	rcu_periph_clock_enable(RCU_USART0);  // 使能串口0时钟
	
	/* connect port to USARTx_Tx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);

    /* connect port to USARTx_Rx */
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10);
	
	/* configure USART Tx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
	
	/* configure USART Rx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
	
	/*****  485 TX enable  ****/ //pin13--PB13	
	gpio_mode_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_13); //GPIO_OSPEED_2MHZ
	gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_13);
	gpio_bit_set(GPIOB,GPIO_PIN_13); //0-Rx  
	
	// 步骤1-7:
	usart_deinit(USART0);   //reset USART0
	usart_word_length_set(USART0,USART_WL_8BIT);  ///2、配置USART字长
	usart_stop_bit_set(USART0,USART_STB_1BIT);  ///3、配置USART停止位
	usart_parity_config(USART0, USART_PM_NONE);//4、奇偶校验位
	usart_baudrate_set(USART0,115200);  ///5、配置USART波特率
	usart_transmit_config(USART0,USART_TRANSMIT_ENABLE);  // 6、USART发送配置
	usart_receive_config(USART0,USART_RECEIVE_ENABLE);
		
	usart_enable(USART0);//使能串口	
	
	// 在nvic中配置中断向量和中断优先级
	nvic_irq_enable(USART0_IRQn,1); //使能NVIC的中断
	// 使能USART子中断   
	usart_interrupt_enable(USART0,USART_INT_RBNE);
}

// 中断处理函数
void USART0_IRQHandler(void)
{	
	// 串口2外部给串口2发送了数据,就会进入下面这个中断,然后把数据读取到data里面
	if( RESET != usart_interrupt_flag_get(USART0,USART_INT_FLAG_RBNE) )// 发生中断,则返回RESET
	{
		 usart_data_receive(USART0); // 读取串口接收到的数据		
	}
	usart_interrupt_flag_clear(USART0,USART_INT_FLAG_ERR_FERR);

}

/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
    usart_data_transmit(USART0, (uint8_t)ch);
    while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
    return ch;
}

************ 版权所有,转载请注明出处 ************
共同监督,一起努力!!!

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值