文章目录
- 1、开箱
- 2、硬件设计
- 3、点灯初试
- 4、gpio输入和中断
- 5、定时器基本定时
- 6、定时器输出PWM
- 7、串口使用
- 8、ADC和DAC测试
- 9、IIC驱动OLED测试
- 10、SPI驱动测试
- 11、总结
1、开箱
最近官方给寄了板子,顺便测评一下吧,首先是开箱环节
板子是调试器+开发板的布局,接口上用了typec接口好评
默认的是个流水灯的效果,来看个图
现在来了解下这个板子,资料的话参考这个官网的数据吧
https://www.arterytek.com/cn/product/AT32F423.jsp#Resource
这个芯片还是不错的,主打一个国产替代
这个是开发板的资料,直接下载这个压缩包就能拿到开发板的相关资料了
下面是keil的pack包,如果用keil开发的话就下载这个包然后安装就行了
让人比较惊喜的是这个,这是个开发工具,大概流程有点像stm32的cube的那一套了
如果用官方的工具来开发的话,大概流程是这样的:
· 1、先用下面的工具生成代码
· 2、使用at32ide写代码
编译和调试也都可以走at32ide来实现
当然也可以用keil来弄,只要在这个里面选一下使用mdk来生成就行了
之后就能打开了,编译也是正常的
调试器用默认的这个dsp就行
直接下载OK
2、硬件设计
看一下测评的这个开发板的参数吧,这个软件还挺好用的,打开就这样了
这个板子主频还不错,有150mhz,比st的一些f4的板子都要好了,时钟树如下
下面看下硬件吧,板子是核心板加调试器的布局,调试器也是一个at32的mcu,型号如下所示:
然后是核心板
5v-3.3v的ldo电路
再关注一下这里的按键和led
3、点灯初试
这里我们先用at32 ide来尝试吧,但是我感觉这个ide不太好用,有缺点,这个我们后面再说,先配置一下led
设置一下这三个led即可
可以在工具的代码预览看到代码
下面使用ide来打开,这里选择导入我们刚刚生成的工程
选择现有项目
之后选定刚刚的路径即可
打开工程就是这样了
点击左上角的锤子图标编译通过
下载的话要配置一下先
跟我一样就行
下载软件
如果要debug,就点击这个虫子就行,跑起来是这个样子
如果要添加自己的文件,尽量用这三个
包含路径就是属性里面的这个
当然也可以用keil来开发,生成代码的时候选一下mdk就行了
打开项目是这样的
下面开始点个灯,在固件库里面找到这个函数
然后它本身也有个延时函数,是这个wk_system.c里面的
代码大概就是这样的,就是循环亮三个灯了
但是我觉得他这个官方的延时函数不是很好用,就模仿正点原子重新弄了一套,基于嘀嗒定时器实现的,需要的自取,代码如下:
systick.c
/*
* systick.c
*
* Created on: 2024 Aug 5
* Author: lx
*/
/**
**************************************************************************
* @file at32f423_board.c
* @brief set of firmware functions to manage leds and push-button.
* initialize delay function.
**************************************************************************
* Copyright notice & Disclaimer
*
* The software Board Support Package (BSP) that is made available to
* download from Artery official website is the copyrighted work of Artery.
* Artery authorizes customers to use, copy, and distribute the BSP
* software and its related documentation for the purpose of design and
* development in conjunction with Artery microcontrollers. Use of the
* software is governed by this copyright notice and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
* GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
* TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
* STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
* INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
*
**************************************************************************
*/
#include "systick.h"
/** @addtogroup AT32F423_board
* @{
*/
/** @defgroup BOARD
* @brief onboard periph driver
* @{
*/
/* delay macros */
#define STEP_DELAY_MS 50
/* delay variable */
static __IO uint32_t fac_us;
static __IO uint32_t fac_ms;
/**
* @brief initialize delay function
* @param none
* @retval none
*/
void delay_init()
{
/* configure systick */
systick_clock_source_config(SYSTICK_CLOCK_SOURCE_AHBCLK_NODIV);
fac_us = system_core_clock / (1000000U);
fac_ms = fac_us * (1000U);
}
/**
* @brief inserts a delay time.
* @param nus: specifies the delay time length, in microsecond.
* @retval none
*/
void delay_us(uint32_t nus)
{
uint32_t temp = 0;
SysTick->LOAD = (uint32_t)(nus * fac_us);
SysTick->VAL = 0x00;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk ;
do
{
temp = SysTick->CTRL;
}while((temp & 0x01) && !(temp & (1 << 16)));
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
SysTick->VAL = 0x00;
}
/**
* @brief inserts a delay time.
* @param nms: specifies the delay time length, in milliseconds.
* @retval none
*/
void delay_ms(uint16_t nms)
{
uint32_t temp = 0;
while(nms)
{
if(nms > STEP_DELAY_MS)
{
SysTick->LOAD = (uint32_t)(STEP_DELAY_MS * fac_ms);
nms -= STEP_DELAY_MS;
}
else
{
SysTick->LOAD = (uint32_t)(nms * fac_ms);
nms = 0;
}
SysTick->VAL = 0x00;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
do
{
temp = SysTick->CTRL;
}while((temp & 0x01) && !(temp & (1 << 16)));
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
SysTick->VAL = 0x00;
}
}
/**
* @brief inserts a delay time.
* @param sec: specifies the delay time, in seconds.
* @retval none
*/
void delay_sec(uint16_t sec)
{
uint16_t index;
for(index = 0; index < sec; index++)
{
delay_ms(500);
delay_ms(500);
}
}
/**
* @}
*/
/**
* @}
*/
systick.h
/*
* systick.h
*
* Created on: 2024 Aug 5
* Author: lx
*/
#ifndef SYSTICK_H_
#define SYSTICK_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stdio.h"
#include "at32f423.h"
/* delay function */
void delay_init(void);
void delay_us(uint32_t nus);
void delay_ms(uint16_t nms);
void delay_sec(uint16_t sec);
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* SYSTICK_H_ */
需要的话就添加如下:
使用逻辑分析仪测量,跟实际上的差了3ms
4、gpio输入和中断
上面的led算是gpio输出了,这个来看一下gpio输入吧,还是使用自家的图形化配置工具,选择pin,可以看到之前设置过的gpio
点开可以看到具体的io设置
这里我们的按键是PA0引脚,看电路默认是下拉的,按下后触发高电平
这里选一下下拉模式
保存代码后查看也能看到我们的修改
下面开始实现按键修改led状态,去库里面查找,应该就是这个函数了
简单实现一个轮询的方式,代码如下:
烧录后正常运行
下面实现一下中断触发吧,先还是在这里配置一下
上升沿
设置为下拉
最后开启一下中断
生成代码,然后打开,已经有中断的程序了
中断回调函数也自己生成了
把之前的逻辑放到这里,看下效果,也能实现按键触发中断
效果如下
5、定时器基本定时
下面实现一下定时器的基本定时功能,查看一下大概有这么多
数据手册中描述如下:
跟stm32比较相似,因此可以采用定时器6/7实现一个基本的定时器设置如下图(这样生成的时间是1ms一次的溢出)
其实我发现他这里还有个图,这个图就很直观了,对新手很友好
然后记得开中断
下面实现一下定时器点灯,下面的逻辑也是1s闪烁一次了
但是发现跑不起来,后面查了一下资料才发现原来有bug,要在这里加一行这个才行。
也用逻辑分析仪跑一下
6、定时器输出PWM
之前设置led的时候,发现这个led其实还绑定着pwm呢,例如下面的这个PD15,就绑定了TMR4的4通道,因此可以来测试一下这个定时器,这三个通道分别对应定时器4的的234通道,在下面设置一下
开启定时器
设置模式
使用下面的函数设置占空比
使用下面的函数设置占空比
逻辑分析仪测一下
在定时器的循环里面实现一下流水灯
效果如下:
7、串口使用
下面测试一下串口中断,在配置工具上开启这个中断
加入下面的回环测试程序
#define UART_BUFFER_LEN 20
uint8_t uart_buffer[UART_BUFFER_LEN] = {0};
uint8_t uart_rxindex = 0;
uint8_t uart_rxlen = 0;
uint8_t uart_txindex = 0;
uint8_t uart_txlen = 0;
void starttx()
{
uart_txlen += uart_rxlen;
uart_rxlen = 0;
usart_interrupt_enable(USART1, USART_TDBE_INT, TRUE);
}
void USART1_IRQHandler(void)
{
/* add user code begin USART1_IRQ 0 */
if(usart_flag_get(USART1, USART_RDBF_FLAG) != RESET)
{
usart_flag_clear(USART1, USART_RDBF_FLAG);
uart_buffer[uart_rxindex++] = usart_data_receive(USART1);
if(uart_rxindex == UART_BUFFER_LEN)
uart_rxindex = 0;
uart_rxlen++;
}
if(usart_flag_get(USART1, USART_IDLEF_FLAG) != RESET || uart_rxlen == UART_BUFFER_LEN/2)
{
usart_flag_clear(USART1, USART_IDLEF_FLAG);
starttx();
}
if(usart_flag_get(USART1, USART_TDBE_FLAG) != RESET)
{
usart_flag_clear(USART1, USART_TDBE_FLAG);
if(uart_txlen > 0)
{
usart_data_transmit(USART1, uart_buffer[uart_txindex++]);
if(uart_txindex == UART_BUFFER_LEN)
uart_txindex = 0;
uart_txlen--;
}
else
{
usart_interrupt_enable(USART1, USART_TDBE_INT, FALSE);
}
}
/* add user code end USART1_IRQ 0 */
/* add user code begin USART1_IRQ 1 */
/* add user code end USART1_IRQ 1 */
}
接上串口,测试结果如下
8、ADC和DAC测试
下面开始测试adc,在图形化配置工具开启adc
这边的默认即可,这里我改到了12位,这样就是0-3.3v对应的0-4096的值
这里生成代码也要注意,开启这个才行
然后每次测试都加上这个
测试结果如下,可以看到adc正常工作
下面来测试使用dma的效果
对三个通道进行如下设置
定义一个数组来临时存储数据
根据生成代码的注释,这里是设置的地址
周期开启dma转换,开启中断和adc的转换
中断进行如下设置,就是在dma拿到数据后更新数据
下载测试结果如下:
下面测试dac,在配置工具中开启dac
这里直接设置默认就行
尝试设置一下电压
用万用表测量电压准确,实际上这个还有很多好玩的,可以生成噪声信号,正弦信号啥的,直接可以用,应该是sdk里面提供的,还是很舒服的。
9、IIC驱动OLED测试
开启iic,配置如下
这里面最坑的一点在这里,就是这个库里面没有常用的iic的函数
得加入这个库才行
这个库的函数如下,这才是我们要用的库
但是这个库又跟dma绑定了,所以为了防止编译错误,要开启这个才行
之后加入iic的驱动
#include "iic.h"
#include "i2c_application.h"
#define I2Cx_ADDRESS 0x78
#define I2Cx_PORT I2C1
#define I2Cx_CLK CRM_I2C1_PERIPH_CLOCK
#define I2Cx_DMA DMA1
#define I2Cx_DMA_CLK CRM_DMA1_PERIPH_CLOCK
#define I2Cx_SCL_GPIO_CLK CRM_GPIOB_PERIPH_CLOCK
#define I2Cx_SCL_GPIO_PIN GPIO_PINS_6
#define I2Cx_SCL_GPIO_PinsSource GPIO_PINS_SOURCE6
#define I2Cx_SCL_GPIO_PORT GPIOB
#define I2Cx_SCL_GPIO_MUX GPIO_MUX_4
#define I2Cx_SDA_GPIO_CLK CRM_GPIOB_PERIPH_CLOCK
#define I2Cx_SDA_GPIO_PIN GPIO_PINS_7
#define I2Cx_SDA_GPIO_PinsSource GPIO_PINS_SOURCE7
#define I2Cx_SDA_GPIO_PORT GPIOB
#define I2Cx_SDA_GPIO_MUX GPIO_MUX_4
#define I2Cx_CLKCTRL 0x10F03C6A //200K
i2c_handle_type hi2cx;
/**
* @brief initializes peripherals used by the i2c.
* @param none
* @retval none
*/
void i2c_lowlevel_init(i2c_handle_type *hi2c)
{
gpio_init_type gpio_init_structure;
if (hi2c->i2cx == I2Cx_PORT) {
/* i2c periph clock enable */
crm_periph_clock_enable(I2Cx_CLK, TRUE);
crm_periph_clock_enable(I2Cx_SCL_GPIO_CLK, TRUE);
crm_periph_clock_enable(I2Cx_SDA_GPIO_CLK, TRUE);
/* gpio configuration */
gpio_pin_mux_config(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_GPIO_PinsSource, I2Cx_SCL_GPIO_MUX);
gpio_pin_mux_config(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_GPIO_PinsSource, I2Cx_SDA_GPIO_MUX);
/* configure i2c pins: scl */
gpio_init_structure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_structure.gpio_mode = GPIO_MODE_MUX;
gpio_init_structure.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
gpio_init_structure.gpio_pull = GPIO_PULL_UP;
gpio_init_structure.gpio_pins = I2Cx_SCL_GPIO_PIN;
gpio_init(I2Cx_SCL_GPIO_PORT, &gpio_init_structure);
/* configure i2c pins: sda */
gpio_init_structure.gpio_pins = I2Cx_SDA_GPIO_PIN;
gpio_init(I2Cx_SDA_GPIO_PORT, &gpio_init_structure);
/* config i2c */
i2c_init(hi2c->i2cx, 0x0F, I2Cx_CLKCTRL);
i2c_own_address1_set(hi2c->i2cx, I2C_ADDRESS_MODE_7BIT, I2Cx_ADDRESS);
}
}
void II2CGpioInit(void)
{
#if 0
gpio_init_type gpio_init_struct;
/* enable gpioc periph clock */
crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);
gpio_default_para_init(&gpio_init_struct);
/* gpio output config */
gpio_bits_write(GPIOC, IO_SCL_PIN | IO_SDA_PIN, TRUE);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = IO_SCL_PIN | IO_SDA_PIN;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init(GPIOC, &gpio_init_struct);
#else
gpio_init_type gpio_init_structure;
crm_periph_clock_enable(I2Cx_CLK, TRUE);
crm_periph_clock_enable(I2Cx_SCL_GPIO_CLK, TRUE);
crm_periph_clock_enable(I2Cx_SDA_GPIO_CLK, TRUE);
/* gpio configuration */
gpio_pin_mux_config(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_GPIO_PinsSource, I2Cx_SCL_GPIO_MUX);
gpio_pin_mux_config(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_GPIO_PinsSource, I2Cx_SDA_GPIO_MUX);
/* configure i2c pins: scl */
gpio_init_structure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_structure.gpio_mode = GPIO_MODE_MUX;
gpio_init_structure.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
gpio_init_structure.gpio_pull = GPIO_PULL_UP;
gpio_init_structure.gpio_pins = I2Cx_SCL_GPIO_PIN;
gpio_init(I2Cx_SCL_GPIO_PORT, &gpio_init_structure);
/* configure i2c pins: sda */
gpio_init_structure.gpio_pins = I2Cx_SDA_GPIO_PIN;
gpio_init(I2Cx_SDA_GPIO_PORT, &gpio_init_structure);
hi2cx.i2cx = I2Cx_PORT;
/* i2c config */
i2c_config(&hi2cx);
#endif
}
/*****************************************************************************
* @name :void IIC_Start(void)
* @date :2018-09-13
* @function :start iic bus
* @parameters :None
* @retvalue :None
******************************************************************************/
void IIC_Start(void)
{
OLED_SCL_SET();
OLED_SDA_SET();
OLED_SDA_CLR();
OLED_SCL_CLR();
}
/*****************************************************************************
* @name :void IIC_Stop(void)
* @date :2018-09-13
* @function :stop iic bus
* @parameters :None
* @retvalue :None
******************************************************************************/
void IIC_Stop(void)
{
OLED_SCL_SET();
OLED_SDA_CLR();
OLED_SDA_SET();
}
/*****************************************************************************
* @name :void IIC_Wait_Ack(void)
* @date :2018-09-13
* @function :wait iic ack
* @parameters :None
* @retvalue :None
******************************************************************************/
void IIC_Wait_Ack(void)
{
OLED_SCL_SET();
OLED_SCL_CLR();
}
/*****************************************************************************
* @name :void Write_IIC_Byte(uint8_t IIC_Byte)
* @date :2018-09-13
* @function :Write a byte of content with iic bus
* @parameters :IIC_Byte
* @retvalue :None
******************************************************************************/
void Write_IIC_Byte(uint8_t IIC_Byte)
{
i2c_status_type i2c_status;
#if 0
uint8_t i;
uint8_t m, da;
da = IIC_Byte;
OLED_SCL_CLR();
for (i = 0; i < 8; i++) {
m = da;
m = m & 0x80;
if (m == 0x80) {
OLED_SDA_SET();
} else {
OLED_SDA_CLR();
}
da = da << 1;
OLED_SCL_SET();
OLED_SCL_CLR();
}
#else
uint8_t buff[2] = {0};
buff[0] = IIC_Byte;
i2c_status = i2c_master_transmit(&hi2cx, I2Cx_ADDRESS, buff, 1, 1000);
if (i2c_status != I2C_OK) {
printf("erro send %d", i2c_status);
}
#endif
}
/*****************************************************************************
* @name :void Write_IIC_Command(uint8_t IIC_Command)
* @date :2018-09-13
* @function :Write a byte of command to oled screen
* @parameters :IIC_Command:command to be written
* @retvalue :None
******************************************************************************/
void Write_IIC_Command(uint8_t IIC_Command)
{
i2c_status_type i2c_status;
#if 0
IIC_Start();
Write_IIC_Byte(IIC_SLAVE_ADDR); //Slave address,SA0=0
IIC_Wait_Ack();
Write_IIC_Byte(0x00); //write command
IIC_Wait_Ack();
Write_IIC_Byte(IIC_Command);
IIC_Wait_Ack();
IIC_Stop();
#else
uint8_t buff[2] = {0};
buff[0] = 0x00;
buff[1] = IIC_Command;
i2c_status = i2c_master_transmit(&hi2cx, I2Cx_ADDRESS, buff, 2, 1000);
if (i2c_status != I2C_OK) {
printf("erro send %d", i2c_status);
}
#endif
}
/*****************************************************************************
* @name :void Write_IIC_Data(uint8_t IIC_Data)
* @date :2018-09-13
* @function :Write a byte of data to oled screen
* @parameters :IIC_Data:data to be written
* @retvalue :None
******************************************************************************/
void Write_IIC_Data(uint8_t IIC_Data)
{
i2c_status_type i2c_status;
#if 0
IIC_Start();
Write_IIC_Byte(IIC_SLAVE_ADDR); //D/C#=0; R/W#=0
IIC_Wait_Ack();
Write_IIC_Byte(0x40); //write data
IIC_Wait_Ack();
Write_IIC_Byte(IIC_Data);
IIC_Wait_Ack();
IIC_Stop();
#else
uint8_t buff[2] = {0};
buff[0] = 0x40;
buff[1] = IIC_Data;
i2c_status = i2c_master_transmit(&hi2cx, I2Cx_ADDRESS, buff, 2, 1000);
if (i2c_status != I2C_OK) {
printf("erro send %d", i2c_status);
}
#endif
}
iic.h
#ifndef _IIC_H_
#define _IIC_H_
#include "at32f423.h"
//本测试程序使用的是软件模拟IIC接口驱动
//IIC的数据引脚定义和时钟引脚定义都可以任意修改
//修改引脚定义后,需要对应修改oled.c中OLED_Init_GPIO函数里面引脚初始化
//定义IIC从设备地址:OLED上设置的访问地址为0x78
#define IIC_SLAVE_ADDR 0x78
//--------------IIC端口操作定义---------------------
#define IO_SCL_PIN GPIO_PINS_2
#define IO_SCL_GPIO_PORT GPIOC
#define IO_SDA_PIN GPIO_PINS_3
#define IO_SDA_GPIO_PORT GPIOC
#define OLED_SDA_SET() gpio_bits_write(IO_SCL_GPIO_PORT, IO_SDA_PIN, TRUE)
#define OLED_SDA_CLR() gpio_bits_write(IO_SCL_GPIO_PORT, IO_SDA_PIN, FALSE)
#define OLED_SCL_SET() gpio_bits_write(IO_SCL_GPIO_PORT, IO_SCL_PIN, TRUE)
#define OLED_SCL_CLR() gpio_bits_write(IO_SCL_GPIO_PORT, IO_SCL_PIN, FALSE)
//IIC操作函数
void II2CGpioInit(void);
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Wait_Ack(void);
void Write_IIC_Byte(uint8_t IIC_Byte);
void Write_IIC_Command(uint8_t IIC_Command);
void Write_IIC_Data(uint8_t IIC_Data);
#endif
使用下面代码测试
实现如下效果
10、SPI驱动测试
这里用一个spi的屏幕来测试spi,驱动是st7735
驱动代码如下
#include "lcd_init.h"
#include "systick.h"
//#define delay_ms delay_1ms
/******************************************************************
* 函 数 名 称:LCD_GPIO_Init
* 函 数 说 明:对LCD引脚初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:注意是使用软件SPI还是硬件SPI
******************************************************************/
void LCD_GPIO_Init(void)
{
#if USE_SOFTWARE
/* 使能时钟 */
// rcu_periph_clock_enable(RCU_LCD_CLK);
// rcu_periph_clock_enable(RCU_LCD_MOS);
// rcu_periph_clock_enable(RCU_LCD_CS);
// rcu_periph_clock_enable(RCU_LCD_DC);
// rcu_periph_clock_enable(RCU_LCD_RES);
// rcu_periph_clock_enable(RCU_LCD_BLK);
//
// gpio_init(PORT_LCD_CLK, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_LCD_CLK);
// gpio_bit_write(PORT_LCD_CLK, GPIO_LCD_CLK, SET);
//
// gpio_init(PORT_LCD_MOS, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_LCD_MOS);
// gpio_bit_write(PORT_LCD_MOS, GPIO_LCD_MOS, SET);
//
// gpio_init(PORT_LCD_DC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_LCD_DC);
// gpio_bit_write(PORT_LCD_DC, GPIO_LCD_DC, SET);
// gpio_init(PORT_LCD_RES, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_LCD_RES);
// gpio_bit_write(PORT_LCD_RES, GPIO_LCD_RES, SET);
// gpio_init(PORT_LCD_BLK, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_LCD_BLK);
// gpio_bit_write(PORT_LCD_BLK, GPIO_LCD_BLK, SET);
// gpio_init(PORT_LCD_CS, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_LCD_CS);
// gpio_bit_write(PORT_LCD_CS, GPIO_LCD_CS, SET);
#else
spi_parameter_struct spi_init_struct;
rcu_periph_clock_enable(RCU_LCD_CLK);
rcu_periph_clock_enable(RCU_LCD_MOS);
rcu_periph_clock_enable(RCU_LCD_CS);
rcu_periph_clock_enable(RCU_LCD_DC);
rcu_periph_clock_enable(RCU_LCD_RES);
rcu_periph_clock_enable(RCU_LCD_BLK);
rcu_periph_clock_enable(RCU_SPI_HARDWARE); // 使能SPI
rcu_periph_clock_enable(RCU_AF);
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
gpio_init(PORT_LCD_DC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_LCD_DC);
gpio_bit_write(PORT_LCD_DC, GPIO_LCD_DC, SET);
gpio_init(PORT_LCD_RES, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_LCD_RES);
gpio_bit_write(PORT_LCD_RES, GPIO_LCD_RES, SET);
gpio_init(PORT_LCD_BLK, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_LCD_BLK);
gpio_bit_write(PORT_LCD_BLK, GPIO_LCD_BLK, SET);
gpio_init(PORT_LCD_CS, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_LCD_CS);
gpio_bit_write(PORT_LCD_CS, GPIO_LCD_CS, SET);
/* 配置 SPI 参数 */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; // 传输模式全双工
spi_init_struct.device_mode = SPI_MASTER; // 配置为主机
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT; // 8位数据
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
spi_init_struct.nss = SPI_NSS_SOFT; // 软件cs
spi_init_struct.prescale = SPI_PSC_32;//2分频
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(PORT_SPI, &spi_init_struct);
/* 使能 SPI */
spi_enable(PORT_SPI);
#endif
}
/******************************************************************
* 函 数 名 称:LCD_Writ_Bus
* 函 数 说 明:LCD串行数据写入函数
* 函 数 形 参:dat 要写入的串行数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:注意是使用软件SPI还是硬件SPI
******************************************************************/
void LCD_Writ_Bus(u8 dat)
{
#if USE_SOFTWARE
u8 i;
LCD_CS_Clr();
for (i = 0; i < 8; i++) {
LCD_SCLK_Clr();
if (dat & 0x80) {
LCD_MOSI_Set();
} else {
LCD_MOSI_Clr();
}
LCD_SCLK_Set();
dat <<= 1;
}
LCD_CS_Set();
#else
LCD_CS_Clr();
while (RESET == spi_i2s_flag_get(PORT_SPI, SPI_FLAG_TBE));
spi_i2s_data_transmit(PORT_SPI, dat);
while (RESET == spi_i2s_flag_get(PORT_SPI, SPI_FLAG_RBNE));
spi_i2s_data_receive(PORT_SPI);
LCD_CS_Set();
#endif
}
/******************************************************************
* 函 数 名 称:LCD_WR_DATA8
* 函 数 说 明:LCD写入8位数据
* 函 数 形 参:dat 写入的数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void LCD_WR_DATA8(u8 dat)
{
LCD_Writ_Bus(dat);
}
/******************************************************************
* 函 数 名 称:LCD_WR_DATA
* 函 数 说 明:LCD写入16位数据
* 函 数 形 参:dat 写入的数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void LCD_WR_DATA(u16 dat)
{
LCD_Writ_Bus(dat >> 8);
LCD_Writ_Bus(dat);
}
/******************************************************************
* 函 数 名 称:LCD_WR_REG
* 函 数 说 明:LCD写入命令
* 函 数 形 参:dat 写入的命令
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void LCD_WR_REG(u8 dat)
{
LCD_DC_Clr();//写命令
LCD_Writ_Bus(dat);
LCD_DC_Set();//写数据
}
/******************************************************************
* 函 数 名 称:LCD_Address_Set
* 函 数 说 明:设置起始和结束地址
* 函 数 形 参:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void LCD_Address_Set(u16 x1, u16 y1, u16 x2, u16 y2)
{
if (USE_HORIZONTAL == 0) {
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1 + 2);
LCD_WR_DATA(x2 + 2);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1 + 1);
LCD_WR_DATA(y2 + 1);
LCD_WR_REG(0x2c);//储存器写
} else if (USE_HORIZONTAL == 1) {
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1 + 2);
LCD_WR_DATA(x2 + 2);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1 + 1);
LCD_WR_DATA(y2 + 1);
LCD_WR_REG(0x2c);//储存器写
} else if (USE_HORIZONTAL == 2) {
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1 + 1);
LCD_WR_DATA(x2 + 1);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1 + 2);
LCD_WR_DATA(y2 + 2);
LCD_WR_REG(0x2c);//储存器写
} else {
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1 + 1);
LCD_WR_DATA(x2 + 1);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1 + 2);
LCD_WR_DATA(y2 + 2);
LCD_WR_REG(0x2c);//储存器写
}
}
/******************************************************************
* 函 数 名 称:LCD_Init
* 函 数 说 明:LCD初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void LCD_Init(void)
{
LCD_GPIO_Init();//初始化GPIO
LCD_RES_Clr();//复位
delay_ms(100);
LCD_RES_Set();
delay_ms(100);
LCD_BLK_Set();//打开背光
delay_ms(100);
//************* Start Initial Sequence **********//
LCD_WR_REG(0x11); //Sleep out
delay_ms(120); //Delay 120ms
//------------------------------------ST7735S Frame Rate-----------------------------------------//
LCD_WR_REG(0xB1);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x3C);
LCD_WR_REG(0xB2);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x3C);
LCD_WR_REG(0xB3);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x3C);
//------------------------------------End ST7735S Frame Rate---------------------------------//
LCD_WR_REG(0xB4); //Dot inversion
LCD_WR_DATA8(0x03);
//------------------------------------ST7735S Power Sequence---------------------------------//
LCD_WR_REG(0xC0);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x04);
LCD_WR_REG(0xC1);
LCD_WR_DATA8(0XC0);
LCD_WR_REG(0xC2);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0xC3);
LCD_WR_DATA8(0x8D);
LCD_WR_DATA8(0x2A);
LCD_WR_REG(0xC4);
LCD_WR_DATA8(0x8D);
LCD_WR_DATA8(0xEE);
//---------------------------------End ST7735S Power Sequence-------------------------------------//
LCD_WR_REG(0xC5); //VCOM
LCD_WR_DATA8(0x1A);
LCD_WR_REG(0x36); //MX, MY, RGB mode
if (USE_HORIZONTAL == 0) {
LCD_WR_DATA8(0x00);
} else if (USE_HORIZONTAL == 1) {
LCD_WR_DATA8(0xC0);
} else if (USE_HORIZONTAL == 2) {
LCD_WR_DATA8(0x70);
} else {
LCD_WR_DATA8(0xA0);
}
//------------------------------------ST7735S Gamma Sequence---------------------------------//
LCD_WR_REG(0xE0);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x22);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x0A);
LCD_WR_DATA8(0x2E);
LCD_WR_DATA8(0x30);
LCD_WR_DATA8(0x25);
LCD_WR_DATA8(0x2A);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x26);
LCD_WR_DATA8(0x2E);
LCD_WR_DATA8(0x3A);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0x13);
LCD_WR_REG(0xE1);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x16);
LCD_WR_DATA8(0x06);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x2D);
LCD_WR_DATA8(0x26);
LCD_WR_DATA8(0x23);
LCD_WR_DATA8(0x27);
LCD_WR_DATA8(0x27);
LCD_WR_DATA8(0x25);
LCD_WR_DATA8(0x2D);
LCD_WR_DATA8(0x3B);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x13);
//------------------------------------End ST7735S Gamma Sequence-----------------------------//
LCD_WR_REG(0x3A); //65k mode
LCD_WR_DATA8(0x05);
LCD_WR_REG(0x29); //Display on
}
lcd_init.h
#ifndef __LCD_INIT_H
#define __LCD_INIT_H
#include "at32f423.h"
#ifndef u8
#define u8 uint8_t
#endif
#ifndef u16
#define u16 uint16_t
#endif
#ifndef u32
#define u32 uint32_t
#endif
#define USE_SOFTWARE 1 //是否使用软件SPI 0使用硬件SPI 1使用软件SPI
#define USE_HORIZONTAL 1 //设置横屏或者竖屏显示 0或1为竖屏 2或3为横屏
#if USE_HORIZONTAL==0||USE_HORIZONTAL==1
#define LCD_W 128
#define LCD_H 160
#else
#define LCD_W 160
#define LCD_H 128
#endif
//#define TCLK PBout(13) //PB13 SCLK--
//#define TDIN PBout(15) //PB15 MOSI--
//#define DOUT PBin(14) //PB14 MISO--
//#define TCS PGout(6) //PG6 CS2--
//#define PEN PGin(7) //PG7 INT--
//-----------------LCD端口移植----------------
//GND - GND
//VCC - 3.3V
//CLK - PB13 SPI1_SCK
//MOS - PB15 SPI1_MOSI
//RES - PD0(可以接入复位)
//DC - PC6
//BLK - PC7- TIMER7_CH0
//MIS - PB14 SPI1_MISO
//CS1 - PB12
//CS2 - PG6
//PEN - PG7
//NC - 不用接
//#define RCU_LCD_CLK RCU_GPIOA//SCK
#define PORT_LCD_CLK GPIOA
#define GPIO_LCD_CLK GPIO_PINS_6
//#define RCU_LCD_MOS RCU_GPIOA//MOSI
#define PORT_LCD_MOS GPIOA
#define GPIO_LCD_MOS GPIO_PINS_7
//#define RCU_LCD_CS RCU_GPIOE//NSS
#define PORT_LCD_CS GPIOE
#define GPIO_LCD_CS GPIO_PINS_10
//#define RCU_LCD_DC RCU_GPIOA //DC
#define PORT_LCD_DC GPIOE
#define GPIO_LCD_DC GPIO_PINS_11
//#define RCU_LCD_RES RCU_GPIOA//RES
#define PORT_LCD_RES GPIOE
#define GPIO_LCD_RES GPIO_PINS_12
//#define RCU_LCD_BLK RCU_GPIOA//BLK
#define PORT_LCD_BLK GPIOE
#define GPIO_LCD_BLK GPIO_PINS_13
/******** 硬件SPI修改此次 ********/
//#define RCU_SPI_HARDWARE RCU_SPI0
//#define PORT_SPI SPI0
//#define LINE_AF_SPI GPIO_PINS_5
//-----------------LCD端口定义----------------
#define LCD_SCLK_Clr() gpio_bits_write(PORT_LCD_CLK, GPIO_LCD_CLK, FALSE)//SCL=SCLK
#define LCD_SCLK_Set() gpio_bits_write(PORT_LCD_CLK, GPIO_LCD_CLK, TRUE)
#define LCD_MOSI_Clr() gpio_bits_write(PORT_LCD_MOS, GPIO_LCD_MOS, FALSE)//SDA=MOSI
#define LCD_MOSI_Set() gpio_bits_write(PORT_LCD_MOS, GPIO_LCD_MOS, TRUE)
#define LCD_RES_Clr() gpio_bits_write(PORT_LCD_RES, GPIO_LCD_RES, FALSE)//RES
#define LCD_RES_Set() gpio_bits_write(PORT_LCD_RES, GPIO_LCD_RES, TRUE)
#define LCD_DC_Clr() gpio_bits_write(PORT_LCD_DC, GPIO_LCD_DC, FALSE)//DC
#define LCD_DC_Set() gpio_bits_write(PORT_LCD_DC, GPIO_LCD_DC, TRUE)
#define LCD_CS_Clr() gpio_bits_write(PORT_LCD_CS, GPIO_LCD_CS, FALSE)//CS
#define LCD_CS_Set() gpio_bits_write(PORT_LCD_CS, GPIO_LCD_CS, TRUE)
#define LCD_BLK_Clr() gpio_bits_write(PORT_LCD_BLK, GPIO_LCD_BLK, FALSE)//BLK
#define LCD_BLK_Set() gpio_bits_write(PORT_LCD_BLK, GPIO_LCD_BLK, TRUE)
void LCD_GPIO_Init(void);//初始化GPIO
void LCD_Writ_Bus(u8 dat);//模拟SPI时序
void LCD_WR_DATA8(u8 dat);//写入一个字节
void LCD_WR_DATA(u16 dat);//写入两个字节
void LCD_WR_REG(u8 dat);//写入一个指令
void LCD_Address_Set(u16 x1, u16 y1, u16 x2, u16 y2); //设置坐标函数
void LCD_Init(void);//LCD初始化
#endif
使用如下代码
测试效果如下
11、总结
首先这个板子性能很强,有stm32F4的水平了,这个没啥问题,然后生态也不错,这个是我觉得很好的地方,这决定了我在一些地方会用这个板子。
但是这个图形化配置工具还是有点bug,比如上次选了勾选全部库,第二次打开就不是了,然后就是iic的bug,希望后续能继续优化,然后希望这个图形化配置工具能融合到ide里面。