一、芯片介绍
1、基础概念
- 内核:32 位的ARM®Cortex®-M4FCPU(学习用到的芯片是 AT32F425R8T7) > 内存(64 K),SRAM(20 K),工作频率最高 96 M
- 特性汇总
所有GPIO口可以映像到16个外部中断(EXINT)
2、配置相关
- keil 配置(按照教程:雅特力AT32F425入门使用指南-电子发烧友网)
- ISP 和 ICP
(一)ISP(在线编程)利用芯片特定通信接口(如 UART、SPI 等),通过简单连接在芯片特定模式下更新固件,常用于成本控制严、功能简单设备 ### (二)ICP(在线电路编程)通过专门接口(如 JTAG、SWD)连接,除编程外还具强大调试功能,应用于对芯片性能和调试要求高的领域如工业自动化、通信等。
- 工程例程打开流程
//1、user里面
- at32f425_clock.c时钟配置文件,设置了默认的时钟频率及时钟路径
- at32f425_int.c中断文件,默认编写了部分内核中断函数的代码流程
- main.c模板工程的主代码文件
//2、bsp里面
- at32f425_board.c板级配置文件,设置了AT-START上的按键和LED等常用硬件配置
//3、firmware里面
- firmware下的at32f425_xx.c是各片上外设的驱动文件
//4、cmsis里面
- system_at32f425.c系统初始化文件
- startup_at32f425.s启动文件
//5、readme里面
- readme.txt工程的说明文件
- 简单工程实例(需要移植文件如下) > firmware 文件中移植了所有外设,其他文件按需要再进行移植
- 宏定义相关
AT32F425R8T7,USE_STDPERIPH_DRIVER,AT_START_F425_V1
3、知识补充
- 注意二进制左高右低
- Hex 文件在 keil 中要配置 output 才会生成
二、格式基础
1、基础代码
- 输入输出,也就是读写
gpio_input_data_bit_read(GPIOA,GPIO_PINS_0)
gpio_bits_write(GPIOC,GPIO_PINS_3,flag);
//看原理图,引脚平时处于低电平,按键按下为高(故为下拉)
void at32_button_init(void) {
gpio_init_type gpio_init_struct; //使能PA0对应时钟
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK,TRUE); //设置为默认值
gpio_default_para_init(&gpio_init_struct); //配置按键
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; //设置为输入模式
gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
gpio_init_struct.gpio_pins = GPIO_PINS_0; //设置为下拉
gpio_init_struct.gpio_pull = GPIO_PULL_DOWN;
gpio_init(GPIOA,&gpio_init_struct);
}
- 中断初始化
```c fold title:中断初始化
//中断初始化
void button_exint_init(void)
{
//外部中断结构体初始化
exint_init_type exint_init_struct;
//GPIOA外设时钟
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
//配置外部时钟
crm_periph_clock_enable(CRM_SCFG_PERIPH_CLOCK, TRUE);
//配置外部中断线(部分产品为GPIO),这里是GPIOA_PIN0
scfg_exint_line_config(SCFG_PORT_SOURCE_GPIOA, SCFG_PINS_SOURCE0);
//外部中断结构体使用默认值
exint_default_para_init(&exint_init_struct);
//中断源使能
exint_init_struct.line_enable = TRUE;
//外部中断线模式为中断模式(不是事件模式)
exint_init_struct.line_mode = EXINT_LINE_INTERRUPT;
//中断源选择
exint_init_struct.line_select = EXINT_LINE_0;
//中断事件
exint_init_struct.line_polarity = EXINT_TRIGGER_RISING_EDGE;
//中断初始化
exint_init(&exint_init_struct);
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4); //配置中断优先级分组
//注意,这里是抢占优先级4位,表示有16种不同的抢占优先级(0-15)
nvic_irq_enable(EXINT1_0_IRQn, 1, 0); //中断服务函数使能
}
- 中断服务函数举例
```c fold title:中断服务函数
//中断服务函数
void EXINT1_0_IRQHandler(void)
{
if(exint_flag_get(EXINT_LINE_0)!=RESET)
{ //等待松手
while(gpio_input_data_bit_read(GPIOA,GPIO_PINS_0)!=1);
flag=(confirm_state)!flag; gpio_bits_write(GPIOC,GPIO_PINS_3,flag);
//清空中断标志位
exint_flag_clear(EXINT_LINE_0);
}
}
-
led 初始化
```c fold title:led初始化 void at32_led_init(void) { //定义一个结构体 gpio_init_type gpio_init_struct; /* 使能对应的外设时钟,这里是LED时钟 clock */ crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE); /* 设置为默认值 */ gpio_default_para_init(&gpio_init_struct); /* 配置相关 */ gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT; gpio_init_struct.gpio_pins = GPIO_PINS_3; gpio_init_struct.gpio_pull = GPIO_PULL_NONE; gpio_init(GPIOC, &gpio_init_struct); }
串口配置相关,写在 com.c 文件里(第二种方法 keil注意勾选这个)
```c fold title:串口配置相关
//方式一:printf重定向
//重定向C库函数printf到DEBUG_USARTx
int fputc(int ch,FILE *f) {
//等待发送缓冲区空闲
while(usart_flag_get(USART1,USART_TDBE_FLAG)==RESET);
usart_data_transmit(USART1,ch); return ch; }
//方式二:串口输出相关配置
#if (__ARMCC_VERSION > 6000000) __asm (“.global __use_no_semihosting);
void _sys_exit(int x)
{
x = x;
}
/* __use_no_semihosting was requested, but _ttywrch was */
void _ttywrch(int ch) {
ch = ch;
} FILE __stdout;
#else
#ifdef __CC_ARM #pragma import(__use_no_semihosting) struct __FILE
{
int handle;
};
FILE __stdout;
void _sys_exit(int x)
{
x = x;
}
/* __use_no_semihosting was requested, but _ttywrch was */
void _ttywrch(int ch) {
ch = ch;
}
#endif
#endif
#if defined (GNUC) && !defined (clang)
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else #define PUTCHAR_PROTOTYPE
int fputc(int ch, FILE *f)
#endif
/** * @brief retargets the c library printf function to the usart. * @param none * @retval none */
PUTCHAR_PROTOTYPE {
while(usart_flag_get(USART1, USART_TDBE_FLAG) == RESET);
usart_data_transmit(USART1, (uint16_t)ch);
while(usart_flag_get(USART1, USART_TDC_FLAG) == RESET);
return ch;
}
#if (defined (GNUC) && !defined (clang)) || (defined (ICCARM))
#if defined (GNUC) && !defined (clang) int _write(int fd, char *pbuffer, int size)
#elif defined ( ICCARM )
#pragma module_name = “?__write” int __write(int fd, char pbuffer, int size)
#endif { for(int i = 0; i < size; i ++) {
while(usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET); usart_data_transmit(PRINT_UART, (uint16_t)(pbuffer++));
while(usart_flag_get(PRINT_UART, USART_TDC_FLAG) == RESET);
}
return size;
}
#endif
- 串口初始化(这里 PA9 为 TX,PA10 为 RX)
```c fold title:串口初始化
//串口初始化
void uart_print_init(uint32_t baudrate)
{
gpio_init_type gpio_init_struct;
//使能外设时钟
crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
gpio_default_para_init(&gpio_init_struct);
//配置串口1 tx引脚
//这里TX PA9,RX PA10
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX; //这个模式只能设置一个,这里是引脚复用功能
gpio_init_struct.gpio_pins = GPIO_PINS_9 | GPIO_PINS_10;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOA, &gpio_init_struct);
//配置串口1 rx引脚
//gpio_init_struct.gpio_mode = GPIO_MODE_INPUT; //注意模式不同,接收模式
//前面设定了PA9的GPIO属性,并没有将PA9引脚的功能设置为串口1的TX功能
gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE9, GPIO_MUX_1); // 将 PA9 设置为 USART1_TX
gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE10, GPIO_MUX_1); // 将 PA10 设置为 USART1_RX
//配置串口1 波特率,数据位数,停止位位数
usart_init(USART1, baudrate, USART_DATA_8BITS, USART_STOP_1_BIT);
//配置校验位
usart_parity_selection_config(USART1,USART_PARITY_NONE);
usart_transmitter_enable(USART1, TRUE);
usart_receiver_enable(USART1,TRUE);
usart_enable(USART1, TRUE); //串口使能
}
(一)串口发送验证
while(USART1->sts_bit.tdbe==0);
(二)串口接收验证
c fold title:
串口接收相关
while(USART1->sts_bit.rdbf==0);
//接收函数举例 while(1) {
while(USART1->sts_bit.rdbf==0);
rx_buf = USART1->dt; if(rx_buf=='1'){
gpio_bits_write(GPIOC,GPIO_PINS_3,TRUE);
}else if(rx_buf=='2'){
gpio_bits_write(GPIOC,GPIO_PINS_3,FALSE);
}
}
(三)串口中断
``c fold title:串口中断相关配置 //中断配置相关 nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
nvic_irq_enable(USART1_IRQn,0,0); //使能中断 usart_interrupt_enable(USART1,USART_RDBF_INT,TRUE);
//中断服务函数 void USART1_IRQHandler(void) { while(usart_flag_get(USART1,USART_RDBF_FLAG)==RESET);
rx_buf = usart_data_receive(USART1);
if(rx_buf==‘1’){ gpio_bits_write(GPIOC,GPIO_PINS_3,TRUE);
}else if(rx_buf==‘2’){ gpio_bits_write(GPIOC,GPIO_PINS_3,FALSE);
} }
三、错误相关
1、GNU 扩展格式重复定义
- 把这个勾去掉就行了
四、定时器
1、TMR 相关
- AT32F425 最多1个高级定时器、7个通用定时器和2个基本定时器,以及1个系统滴答定时器
- 基本定时器 TMR 6,7
3、通用定时器 TMR 2,3,13,14,15,16,17
4、高级定时器 TMR 1
五、DMA
1、配置相关
- usart 初始化中加入
```c
//DMA发送使能
usart_dma_transmitter_enable(USART1,TRUE);
//DMA接收使能
usart_dma_receiver_enable(USART1,TRUE);
dma 初始化 ###
(一)详细配置
```c fold title:dma轮询 uint8_t tx_buf[] = “Hello World”; #define COUNTOF(a) (sizeof(a) / sizeof(*(a)))
//注意部分配置写在串口初始化里 //发送通道1,接收通道2 void Driver_dma_init(void) { dma_init_type dma_init_struct; /使能DMA外设时钟/ crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE); /* DMA1通道1模式配置/ dma_reset(DMA1_CHANNEL1); dma_reset(DMA1_CHANNEL2); dma_default_para_init(&dma_init_struct);
/容量配置/ dma_init_struct.buffer_size =COUNTOF(tx_buf)-1;
/方向:由内存到外设/ dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
/内存地址*/ dma_init_struct.memory_base_addr = (uint32_t)tx_buf;
dma_init_struct.memory_data_width = DMA_ME
MORY_DATA_WIDTH_BYTE; dma_init_struct.memory_inc_enable = TRUE;
dma_init_struct.peripheral_base_addr = (uint32_t)&(USART1->dt);
dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
dma_init_struct.peripheral_inc_enable = FALSE; dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
dma_init_struct.loop_mode_enable = FALSE;
dma_init(DMA1_CHANNEL1, &dma_init_struct);
dma_init(DMA1_CHANNEL2, &dma_init_struct);
/DMA1弹性配置/ dma_flexible_config(DMA1,FLEX_CHANNEL1, DMA_FLEXIBLE_UART1_RX);
dma_flexible_config(DMA1,FLEX_CHANNEL2, DMA_FLEXIBLE_UART1_TX);
/DMA1通道1中断使能/ dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
dma_interrupt_enable(DMA1_CHANNEL2, DMA_FDT_INT, TRUE);
/中断的初始化/ nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
nvic_irq_enable(DMA1_Channel1_IRQn, 1, 0);
nvic_irq_enable(DMA1_Channel3_2_IRQn, 0, 0);
/DMA1通道1关闭,通道2打开/
dma_channel_enable(DMA1_CHANNEL1, FALSE);
dma_channel_enable(DMA1_CHANNEL2, TRUE); }
(二)基本配置
```c fold title:dma基本配置
__IO uint16_t adc1_ordinary_valuetab[10][3] = {0};
__IO uint16_t dma_trans_complete_flag = 0;
void Driver_dma_init(void)
{
dma_init_type dma_init_struct;
/*使能DMA外设时钟*/
crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
/* DMA1通道1模式配置*/
/*dma中断分组*/
nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0);
dma_reset(DMA1_CHANNEL1);
dma_default_para_init(&dma_init_struct);
/*长度设置为30*/
dma_init_struct.buffer_size = 30;
/*方向设置为外设到内存*/
dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
/*设置内存地址*/
dma_init_struct.memory_base_addr = (uint32_t)adc1_ordinary_valuetab;
/*设置字节宽度为16bit,因为adc是12bit的*/
dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
/*开启内存增量模式*/
dma_init_struct.memory_inc_enable = TRUE;
/*设置外设地址*/
dma_init_struct.peripheral_base_addr = (uint32_t)&(ADC1->odt);
/*字节宽度同上*/
dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
/*关闭增量模式*/
dma_init_struct.peripheral_inc_enable = FALSE;
/*dma仲裁优先级最高*/
dma_init_struct.priority = DMA_PRIORITY_HIGH;
/*循环模式关闭*/
dma_init_struct.loop_mode_enable = FALSE;
/*初始化*/
dma_init(DMA1_CHANNEL1, &dma_init_struct);
/*dma中断开启*/
dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
/*通道1使能*/
dma_channel_enable(DMA1_CHANNEL1, TRUE);
}
- 两个中断服务函数:发送通道与接收通道
c fold title:两个中断服务函数
confirm_state flag = TRUE;
void DMA1_Channel1_IRQHandler(void) { if(dma_flag_get(DMA1_FDT1_FLAG)) { dma_flag_clear(DMA1_FDT1_FLAG); flag=(confirm_state)!flag;
gpio_bits_write(GPIOC,GPIO_PINS_3,flag);
/关闭DMA通道/ dma_channel_enable(DMA1_CHANNEL1, FALSE);
/重写装载/ DMA1_CHANNEL1->dtcnt =COUNTOF(tx_buf)-1;
/开启DMA传输/ dma_channel_enable(DMA1_CHANNEL2, TRUE);
}
}
void DMA1_Channel3_2_IRQHandler(void) {
if(dma_flag_get(DMA1_FDT2_FLAG)) {
dma_flag_clear(DMA1_FDT2_FLAG);
flag=(confirm_state)!flag;
gpio_bits_write(GPIOD,GPIO_PINS_3,flag);
/关闭DMA通道/ dma_channel_enable(DMA1_CHANNEL2, FALSE);
/重写装载/ DMA1_CHANNEL2->dtcnt =COUNTOF(tx_buf)-1;
/开启DMA传输/ dma_channel_enable(DMA1_CHANNEL2, TRUE);
if(tx_buf[0]==‘H’&&tx_buf[1]==‘e’)
dma_channel_enable(DMA1_CHANNEL1, TRUE);
}
}
五、ADC
1、ADC 原理
- 测得电压参考电压,常规转换和注入通道的转换
六、SPI
- 后面代码过多就没上传了哈哈,可以私信