1. 前言:
感谢平台给我这个评测的机会。
我非常珍惜这次评测和学习的机会。
这是第一次接触国民技术的产品,还需要时间不断的来学习。
也希望后续有机会学习和认识更多更好的产品。
2. 评测总结
1-这个板子自带下载器,这个必须点赞,对比别家的没有是下载器,在构建环境的时候,实在太麻烦了。
2-这个板子自带CH340,这个也必须点赞,因为这个在调试的时候,下载和输出信息只需要一根USB线,就这一点秒杀很多开发板啊。真正的做到了简单易用,虽然这个增加了硬件成本,但是真的是为入门选手节省了宝贵时间。
3-板子的每个IO都引出了,并且可以直接焊接双排针,这点太贴心了,真的让人喜欢啊。
4-预留了4路上拉和下拉4.7K电路,方便飞线使用,再也不用自己去焊接电阻了,非常方便测试
5-demo程序非常加单移动,非常方便拿来直接使用。各个功能模块都有很好的例程。
6-这是一款非常贴心的开发板,诚意满满,非常适合入门学习各个功能模块。
3. 认识国民技术开发板
N32G401系列采用32-bit Arm® Cortex®-M4F内核,最高工作主频72MHz,支持浮点运算和DSP指令,集成高达64KB嵌入式加密Flash,8KB SRAM,集成丰富的高性能模拟器件,内置1个12bit 4.2Msps ADC,3个高速比较器,集成4个U(S)ART、2个I2C、2个SPI等数字通信接口。有14个子型号可供选择,可广泛应用于电控、照明、扫地机、无线充、智能门锁、车身电子、无线麦克风、报警装置等领域。
(1)高性能,低功耗:芯片采用Arm® Cortex®-M4F内核,运行主频72MHz,内置1KB指令缓存,CoreMark跑分达235.8,浮点运算能力达90DMIPS;动态运行功耗90uA/MHz,STOP2功耗10uA (25℃最大值)。
(2)高可靠性:工作环境温度-40~105℃,具有双时钟安全监测系统,I/O支持电压钳位,抗静电ESD:±4kV(HBM模型),符合IEC60730标准。
(3)高精度:内置8MHz +/-1%精度RC振荡器,以及12bit 4.2Msps高速高精度ADC。
(4)小尺寸:支持TSSOP/LQFP/QFN等多种封装形式,提供20/28/32/48等管脚封装,最小尺寸3mm*3mm (QFN20封装)。
4. 环境搭建
本人采用Keil5.38作为开发版本。
下载时候需要注意作如下选择下载器:
5. 验证目标
1-实现浮点计算;
2-实现GPIO控制,LED控制亮灭;
3-实现串口通信;
4-实现GPIO中断,在中断函数处理事务:LED控制+串口输出
6. 程序开发
6.1. 串口实现printf
#include "log.h"
#if LOG_ENABLE
#include "n32g401.h"
#define LOG_USARTx USART1
#define LOG_PERIPH RCC_APB2_PERIPH_USART1
#define LOG_GPIO GPIOA
#define LOG_PERIPH_GPIO RCC_AHB_PERIPH_GPIOA
#define LOG_TX_PIN GPIO_PIN_9
#define LOG_RX_PIN GPIO_PIN_10
void log_init(void)
{
GPIO_InitType GPIO_InitStructure;
USART_InitType USART_InitStructure;
RCC_AHB_Peripheral_Clock_Enable(LOG_PERIPH_GPIO);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO | LOG_PERIPH);
GPIO_Structure_Initialize(&GPIO_InitStructure);
GPIO_InitStructure.Pin = LOG_TX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF5_USART1;
GPIO_Peripheral_Initialize(LOG_GPIO, &GPIO_InitStructure);
GPIO_InitStructure.Pin = LOG_RX_PIN;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF5_USART1;
GPIO_Peripheral_Initialize(GPIOA, &GPIO_InitStructure);
USART_InitStructure.BaudRate = 115200;
USART_InitStructure.WordLength = USART_WL_8B;
USART_InitStructure.StopBits = USART_STPB_1;
USART_InitStructure.Parity = USART_PE_NO;
USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
USART_InitStructure.Mode = USART_MODE_TX;
/* init uart */
USART_Initializes(LOG_USARTx, &USART_InitStructure);
/* enable uart */
USART_Enable(LOG_USARTx);
}
static int is_lr_sent = 0;
int fputc(int ch, FILE* f)
{
if (ch == '\r')
{
is_lr_sent = 1;
}
else if (ch == '\n')
{
if (!is_lr_sent)
{
USART_Data_Send(LOG_USARTx, (uint8_t)'\r');
/* Loop until the end of transmission */
while (USART_Flag_Status_Get(LOG_USARTx, USART_FLAG_TXC) == RESET)
{ }
}
is_lr_sent = 0;
}
else
{
is_lr_sent = 0;
}
USART_Data_Send(LOG_USARTx, (uint8_t)ch);
/* Loop until the end of transmission */
while (USART_Flag_Status_Get(LOG_USARTx, USART_FLAG_TXDE) == RESET)
{ }
return ch;
}
6.2. 按键中断实现
#define KEY1_INPUT_PORT GPIOA
#define KEY1_INPUT_PIN GPIO_PIN_4
#define KEY1_INPUT_EXTI_LINE EXTI_LINE4
#define KEY1_INPUT_PORT_SOURCE EXTI_LINE_SOURCE4
#define KEY1_INPUT_PIN_SOURCE AFIO_EXTI_PA4
#define KEY1_INPUT_IRQn EXTI4_IRQn
#define KEY2_INPUT_PORT GPIOA
#define KEY2_INPUT_PIN GPIO_PIN_5
#define KEY2_INPUT_EXTI_LINE EXTI_LINE5
#define KEY2_INPUT_PORT_SOURCE EXTI_LINE_SOURCE5
#define KEY2_INPUT_PIN_SOURCE AFIO_EXTI_PA5
#define KEY2_INPUT_IRQn EXTI9_5_IRQn
#define KEY3_INPUT_PORT GPIOA
#define KEY3_INPUT_PIN GPIO_PIN_6
#define KEY3_INPUT_EXTI_LINE EXTI_LINE6
#define KEY3_INPUT_PORT_SOURCE EXTI_LINE_SOURCE6
#define KEY3_INPUT_PIN_SOURCE AFIO_EXTI_PA6
#define KEY3_INPUT_IRQn EXTI9_5_IRQn
#include "bsp_KEY.h"
void Key1InputExtiInit(void)
{
GPIO_InitType GPIO_InitStructure;
EXTI_InitType EXTI_InitStructure;
NVIC_InitType NVIC_InitStructure;
/* Enable the GPIO Clock */
if (KEY1_INPUT_PORT == GPIOA)
{
CC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOA);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
}
else if (KEY1_INPUT_PORT == GPIOB)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOB);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
}
else if (KEY1_INPUT_PORT == GPIOC)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOC);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
}
else if (KEY1_INPUT_PORT == GPIOD)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOD);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
}
else
{
return;
}
if (KEY1_INPUT_PIN <= GPIO_PIN_ALL)
{
GPIO_Structure_Initialize(&GPIO_InitStructure);
GPIO_InitStructure.Pin = KEY1_INPUT_PIN;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_Peripheral_Initialize(KEY1_INPUT_PORT, &GPIO_InitStructure);
}
/* Configure key EXTI Line to key input Pin */
GPIO_EXTI_Line_Set(KEY1_INPUT_PORT_SOURCE, KEY1_INPUT_PIN_SOURCE);
/* Configure key EXTI line */
EXTI_InitStructure.EXTI_Line = KEY1_INPUT_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Peripheral_Initializes(&EXTI_InitStructure);
/* Set key input interrupt priority */
NVIC_InitStructure.NVIC_IRQChannel = KEY1_INPUT_IRQn;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_SUB_PRIORITY_1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initializes(&NVIC_InitStructure);
}
void Key2InputExtiInit(void)
{
GPIO_InitType GPIO_InitStructure;
EXTI_InitType EXTI_InitStructure;
NVIC_InitType NVIC_InitStructure;
/* Enable the GPIO Clock */
if (KEY2_INPUT_PORT == GPIOA)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOA);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
}
else if (KEY2_INPUT_PORT == GPIOB)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOB);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
}
else if (KEY2_INPUT_PORT == GPIOC)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOC);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
}
else if (KEY2_INPUT_PORT == GPIOD)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOD);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
}
else
{
return;
}
if (KEY2_INPUT_PIN <= GPIO_PIN_ALL)
{
GPIO_Structure_Initialize(&GPIO_InitStructure);
GPIO_InitStructure.Pin = KEY2_INPUT_PIN;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_Peripheral_Initialize(KEY2_INPUT_PORT, &GPIO_InitStructure);
}
/* Configure key EXTI Line to key input Pin */
GPIO_EXTI_Line_Set(KEY2_INPUT_PORT_SOURCE, KEY2_INPUT_PIN_SOURCE);
/* Configure key EXTI line */
EXTI_InitStructure.EXTI_Line = KEY2_INPUT_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Peripheral_Initializes(&EXTI_InitStructure);
/* Set key input interrupt priority */
NVIC_InitStructure.NVIC_IRQChannel = KEY2_INPUT_IRQn;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_SUB_PRIORITY_1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initializes(&NVIC_InitStructure);
}
void Key3InputExtiInit(void)
{
GPIO_InitType GPIO_InitStructure;
EXTI_InitType EXTI_InitStructure;
NVIC_InitType NVIC_InitStructure;
/* Enable the GPIO Clock */
if (KEY3_INPUT_PORT == GPIOA)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOA);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
}
else if (KEY3_INPUT_PORT == GPIOB)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOB);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
}
else if (KEY3_INPUT_PORT == GPIOC)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOC);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
}
else if (KEY3_INPUT_PORT == GPIOD)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOD);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
}
else
{
return;
}
if (KEY3_INPUT_PIN <= GPIO_PIN_ALL)
{
GPIO_Structure_Initialize(&GPIO_InitStructure);
GPIO_InitStructure.Pin = KEY3_INPUT_PIN;
GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
GPIO_Peripheral_Initialize(KEY3_INPUT_PORT, &GPIO_InitStructure);
}
/* Configure key EXTI Line to key input Pin */
GPIO_EXTI_Line_Set(KEY3_INPUT_PORT_SOURCE, KEY3_INPUT_PIN_SOURCE);
/* Configure key EXTI line */
EXTI_InitStructure.EXTI_Line = KEY3_INPUT_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Peripheral_Initializes(&EXTI_InitStructure);
/* Set key input interrupt priority */
NVIC_InitStructure.NVIC_IRQChannel = KEY3_INPUT_IRQn;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_SUB_PRIORITY_1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initializes(&NVIC_InitStructure);
}
void EXTI9_5_IRQHandler(void)
{
if (RESET != EXTI_Interrupt_Status_Get(KEY2_INPUT_EXTI_LINE))
{
LED2_ON;
printf("\nkey2");
EXTI_Interrupt_Status_Clear(KEY2_INPUT_EXTI_LINE);
}
if (RESET != EXTI_Interrupt_Status_Get(KEY3_INPUT_EXTI_LINE))
{
LED1_OFF;LED2_OFF;
printf("\nkey3");
EXTI_Interrupt_Status_Clear(KEY3_INPUT_EXTI_LINE);
}
}
void EXTI4_IRQHandler(void)
{
if (RESET != EXTI_Interrupt_Status_Get(KEY1_INPUT_EXTI_LINE))
{
LED1_ON;
printf("\nkey1");
EXTI_Interrupt_Status_Clear(KEY1_INPUT_EXTI_LINE);
}
}
6.3. LED初始化及定义
/** Define the GPIO port to which the LED is connected **/
#define LED1_GPIO_PORT GPIOA /* GPIO port */
#define LED1_GPIO_CLK RCC_AHB_PERIPH_GPIOA /* GPIO port clock */
#define LED1_GPIO_PIN GPIO_PIN_1 /* GPIO connected to the SCL clock line */
#define LED2_GPIO_PORT GPIOA /* GPIO port */
#define LED2_GPIO_CLK RCC_AHB_PERIPH_GPIOA /* GPIO port clock */
#define LED2_GPIO_PIN GPIO_PIN_7 /* GPIO connected to the SCL clock line */
#define LED3_GPIO_PORT GPIOA /* GPIO port */
#define LED3_GPIO_CLK RCC_AHB_PERIPH_GPIOA /* GPIO port clock */
#define LED3_GPIO_PIN GPIO_PIN_9 /* GPIO connected to the SCL clock line */
/** Define macros that control IO **/
#define LED1_TOGGLE {LED1_GPIO_PORT->POD ^= LED1_GPIO_PIN;}
#define LED1_ON {LED1_GPIO_PORT->PBSC = LED1_GPIO_PIN;}
#define LED1_OFF {LED1_GPIO_PORT->PBC = LED1_GPIO_PIN;}
#define LED2_TOGGLE {LED2_GPIO_PORT->POD ^= LED2_GPIO_PIN;}
#define LED2_ON {LED2_GPIO_PORT->PBSC = LED2_GPIO_PIN;}
#define LED2_OFF {LED2_GPIO_PORT->PBC = LED2_GPIO_PIN;}
#define LED3_TOGGLE {LED3_GPIO_PORT->POD ^= LED3_GPIO_PIN;}
#define LED3_ON {LED3_GPIO_PORT->PBSC = LED3_GPIO_PIN;}
#define LED3_OFF {LED3_GPIO_PORT->PBC = LED3_GPIO_PIN;}
#include "bsp_led.h"
void LED_Initialize(GPIO_Module* GPIOx, uint16_t pin)
{
/* Define a structure of type GPIO_InitType */
GPIO_InitType GPIO_InitStructure;
/* Enable LED related GPIO peripheral clock */
if(GPIOx == GPIOA)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOA);
}
else if(GPIOx == GPIOB)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOB);
}
else if(GPIOx == GPIOC)
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOC);
}
else
{
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOD);
}
if(pin < GPIO_PIN_ALL)
{
/* Assign default value to GPIO_InitStructure structure */
GPIO_Structure_Initialize(&GPIO_InitStructure);
/* Select the GPIO pin to control */
GPIO_InitStructure.Pin = pin;
/* Set pin mode to general push-pull output */
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP;
/* Set the pin drive current to 4MA*/
GPIO_InitStructure.GPIO_Current = GPIO_DS_4MA;
/* Initialize GPIO */
GPIO_Peripheral_Initialize(GPIOx, &GPIO_InitStructure);
}
}
void LED_Toggle(GPIO_Module* GPIOx, uint16_t pin)
{
GPIO_Pin_Toggle(GPIOx, pin);;
}
void LED_On(GPIO_Module* GPIOx,uint16_t pin)
{
GPIO_Pins_Set(GPIOx, pin);
}
void LED_Off(GPIO_Module* GPIOx,uint16_t pin)
{
GPIO_Pins_Reset(GPIOx, pin);
}
6.4. 延时函数实现
ms和us延时实现
#include "bsp_delay.h"
/**
*\*\name DBG_SysTick_Config.
*\*\fun System tick configuration.
*\*\param ticks :system tick
*\*\return none
**/
static uint32_t DBG_SysTick_Config(uint32_t ticks)
{
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
SysTick->VAL = 0; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
return (0); /* Function successful */
}
/**
*\*\name SysTick_Delay_Us.
*\*\fun microsecond delay.
*\*\param us :any number
*\*\return none
**/
void SysTick_Delay_Us( __IO uint32_t us)
{
uint32_t i;
RCC_ClocksType RCC_Clocks;
RCC_Clocks_Frequencies_Value_Get(&RCC_Clocks);
DBG_SysTick_Config(RCC_Clocks.SysclkFreq / 1000000);
for(i=0;i<us;i++)
{
/* When the counter value decreases to 0, bit 16 of the CRTL register will be set to 1 */
/* When set to 1, reading this bit will clear it to 0 */
while( !((SysTick->CTRL)&(1<<16)) );
}
/* Turn off the SysTick timer */
SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}
/**
*\*\name SysTick_Delay_Us.
*\*\fun millisecond delay.
*\*\param ms :any number
*\*\return none
**/
void SysTick_Delay_Ms( __IO uint32_t ms)
{
uint32_t i;
RCC_ClocksType RCC_Clocks;
RCC_Clocks_Frequencies_Value_Get(&RCC_Clocks);
DBG_SysTick_Config(RCC_Clocks.SysclkFreq / 1000);
for(i=0;i<ms;i++)
{
/* When the counter value decreases to 0, bit 16 of the CRTL register will be set to 1 */
/* When set to 1, reading this bit will clear it to 0 */
while( !((SysTick->CTRL)&(1<<16)) );
}
/* Turn off the SysTick timer */
SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}
6.5. 主程序
系统初始化,初始化各个模块。
实现浮点运算,并通过串口输出到上位机
int main(void)
{
double y=0.0;
/* Initialize Led1~Led3 as output push-pull mode */
LED_Initialize(LED1_GPIO_PORT, LED1_GPIO_PIN | LED2_GPIO_PIN );
/* Turn on Led2~Led3 */
LED_On(LED2_GPIO_PORT, LED1_GPIO_PIN |LED2_GPIO_PIN);
/* Delay 1s */
SysTick_Delay_Ms(1000);
/* Turn off Led1~Led3 */
LED_Off(LED1_GPIO_PORT, LED1_GPIO_PIN | LED2_GPIO_PIN);
Key1InputExtiInit();
Key2InputExtiInit();
Key3InputExtiInit();
log_init();
/* Output a message on Hyperterminal using printf function */
printf("\nUSART Printf Example: retarget the C library printf function to the USART");
while (1)
{
SysTick_Delay_Ms(1000);
y=0.11+y;
printf("\ny =%f",y);
}
}
7. 效果验证
7.1. 串口输出
7.2. 按键中断
7.3. LED控制
按键控制KED的亮灭
实验验证视频详见:
演示视频
https://u.eet-china.com/video/3574