打印
[活动专区]

【AT-START-L021测评】带你全方位感受国货之光

[复制链接]
766|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 仗剑天涯1412 于 2024-12-5 21:16 编辑



    首先感谢21ic平台和雅特力的支持,提供了这次测评的机会,让我进一步了解到国产芯片的崛起。    今天测评的这款开发板是AT-START-L021,以AT32L021C8T7芯片为中心,外设配置LED灯,按钮,和ArduinoTM Uno R3扩展接口。此开发板自带嵌入式调试/烧录工具AT-Link-EZ,不需接入额外开发工具即可对芯片调试使用。具有ARM Cortex®-M0+内核的32位微控制器AT32L021的高性能及低功耗特性。话不多说快进到开箱,一整个惊艳:

再来一个高清效果图(图片来源于21ic电子网):





1.生态和工具

    雅特力官网提供了丰富的手册资料和开发工具,助力每一个梦想,传送门:雅特力科技 : 32位微控制器的创新领导者!


    今天测评的AT-START-L021开发板所有工具资料都可以通过链接雅特力科技 : 32位微控制器的创新领导者!获取下载,划重点:开发板都开源啦!!!


    最强大的还得是图形化开发工具AT32 Work Bench,AT32 MCU图形化配置软件,生成初始化C代码。这款软件是免安装的,点击即可使用。下面就一起开启AT32 Work Bench之门:
打开AT32 Work Bench软件首先选择型号,今天的主角--AT32L021C8T7


完成工程创建后就进入到开发界面了,可以自由的定义你想要的功能,完成引脚和外设的初始化。


最让我眼前一亮的还是I2S,小小芯片竟然还支持I2S,在同级别的芯片中很少有支持I2S的芯片。使用起来也相当的容易,因为需要注意待的地方AT32 Work Bench已经全注意到了,直接点点点就完成了初始化。


配置完外设后最重要的灵魂就是时钟,此时如果有一个时钟配置工具就简直不要太开心了,你能想到的,雅特力早就帮你想到了,不仅有专门的时钟配置工具,还集成到了AT32 Work Bench内,一口气完成配置。


duang duang duang一顿输出就完成了初始化配置,还支持代码预览,不用打开层层文件才能看到效果


做痛苦的事莫过于拿到工程文件后,没有固件包,或者固件包版本不匹配,当然这个问题也解决了,可以自由选择导出方式


至此,整个初始化,以及生态和工具都接触到了,生态完善,资料丰富,工具强大,对于开发者来说有很大的支持和帮助。



2.硬件资源:

满满的一页总有一个适合你。雅特力的sLib安全库,硬件CRC校验都很不错,做安全可靠的产品必不可少。


在来看看开发板的整体布局和功能模块:


AT-Link-EZ是开发板自带嵌入式调试/烧录工具,不需接入额外开发工具即可对芯片调试使用(AT-Link-EZ为AT-Link简易版,不支持离线模式)。相当于把调试烧录工具集成到了开发板上,上手更快,无需一堆先缠在一起,无数个条线占用电脑接口。只需要有一根type-C数据线就可以完成烧录和调试。


主控MCU外围电路,实现最小系统。


电源外围电路,提供了LDO电压转换和LED和按键等外设。


排针排母将IO引出方便拓展使用,足够的灵活方便。



雅特力家族有很多款mcu型号,每一款都有属于自己的名字,今天的主角AT32L021C8T7就是其中一员:低功耗,M0+内核,48pin,64K闪存存储器(Flash),8+1KB随机存取存储器(SRAM),LQFP封装,-40℃~105℃。


可以根据封装和Flash大小选择合适的型号:


3.上电运行

    按照下面的顺序配置AT-START-L021板,开始启动应用:

1. 检查板上跳线位置: JP1选择GND或OFF(BOOT0为0,BOOT0在AT32L021C8T7内自带下拉电阻);


2. 用一根USB线(Type-A转Type-C)连接AT-Link-EZ到PC,通过USB连接器CN6给板子供电。LED1(红)恒亮,3个LED灯(LED2到LED4)开始轮留闪烁。


3. 按用户键(B2)后,3个LED灯闪烁频率改变。


肉眼更明显直观。再做进一步开发前,需要先了解开发板的跳线帽,0Ω电阻作用,便于更好的去测试性能。

  • 电源和电源选择     AT-START-L021的5 V电源可通过USB线接上AT-Link-EZ上的USB连接器(CN6)来提供,或者通过一个外部的5 V电源(E5V)提供所需的5 V电源。这时5 V电源通过板上3.3 V电压调节器(U2),或3.3 V通过板上1.8 V电压调节器(U3)提供微控制器及外设所需的3.3 V或1.8 V电源,3.3 V或1.8 V由JP2作选择。 J4或J7的引脚E5V也可用作输入电源,AT-START-L021板子必须由一个5 V供电单元供电。 J4的引脚VDD_MCU或J1和J2引脚VDD也可用作输入电源直接对AT32L021C8T7及其外设供电。 注意: 除非5 V通过AT-Link-EZ上的USB接口(CN6)提供,否则通过其他供电方式AT-Link-EZ并不会被供电而无法使用。 当另一个应用板连接到J4,引脚E5V和VDD_MCU可用作输出电源;J7引脚E5V可用作5 V输出电源;J1和J2引脚VDD可用作3.3 V或1.8 V输出电源。
  • 源和电源选择     AT-START-L021的5 V电源可通过USB线接上AT-Link-EZ上的USB连接器(CN6)来提供,或者通过一个外部的5 V电源(E5V)提供所需的5 V电源。这时5 V电源通过板上3.3 V电压调节器(U2),或3.3 V通过板上1.8 V电压调节器(U3)提供微控制器及外设所需的3.3 V或1.8 V电源,3.3 V或1.8 V由JP2作选择。 J4或J7的引脚E5V也可用作输入电源,AT-START-L021板子必须由一个5 V供电单元供电。 J4的引脚VDD_MCU或J1和J2引脚VDD也可用作输入电源直接对AT32L021C8T7及其外设供电。 注意: 除非5 V通过AT-Link-EZ上的USB接口(CN6)提供,否则通过其他供电方式AT-Link-EZ并不会被供电而无法使用。 当另一个应用板连接到J4,引脚E5V和VDD_MCU可用作输出电源;J7引脚E5V可用作5 V输出电源;J1和J2引脚VDD可用作3.3 V或1.8 V输出电源。
  • 编程和调试:嵌入的AT-Link-EZ    开发板上已集合雅特力AT-Link-EZ编程和调试工具,使用者即可对AT-START-L021板上的AT32L021C8T7进行编程和调试。AT-Link-EZ支持SWD接口模式,并支持一组虚拟串口(VCP)与AT32L021C8T7的USART1_TX/USART1_RX(PA9/PA10)对接。透过电平转换芯片(U4),ATLink-EZ的3.3 V信号电平和微控制器的3.3 V或1.8 V的信号电平可以互相转换对接。 关于AT-Link-EZ的操作、固件升级、和注意事项等详细信息,请参考AT-Link连接器用户手册。 若不使用开发板上的AT-Link-EZ,可将RP2和RP3 OFF使其信号与与AT-START-L021断开。此时AT-START-L021仍可通过CN2接口(出厂未上件)与其它Link对接,也可实现对AT32L021C8T7的编程和调试。
  • 启动模式选择     在启动时,通过对启动引脚配置可以选择三种启动模式中的一种。
  • 外部时钟源
  • HEXT时钟源

有三种硬件方式设置外部高速时钟来源:
  • 板上晶振(出厂默认设置) 板上提供一8 MHz晶振作为HEXT时钟源使用。硬件设置必须为:R26和R27 ON,R28和R29 OFF。
  • 来自PF0外灌 外部振荡从J2第5脚灌入。硬件设置必须为:R28和R29 ON,R26和R27 OFF。
  • HEXT不使用 PF0和PF1作为GPIO使用。硬件设置必须为:R28和R29 ON,R26和R27 OFF。


  • LEXT时钟源
有三种硬件方式设置外部低速时钟来源:
  • 板上晶振(出厂默认设置) 板上提供一32.768 kHz晶振作为LEXT时钟源使用。硬件设置必须为:R22和R23 ON,R24和R25 OFF。
  • 来自PC14外灌 外部振荡从J2第3脚灌入。硬件设置必须为:R24和R25 ON,R22和R23 OFF。
  • LEXT不使用 PC14和PC15作为GPIO使用。硬件设置必须为:R24和R25 ON,R22和R23 OFF

0Ω电阻



4.数据备份
养成一个好习惯,在进行新的开发任务前,对原有的数据进行备份。因为没有出厂程序源码(功能很简单,仅作演示示范),所以可以先读取原有程序进行备份。将type-c数据线连接电脑和开发板,电脑的设备管理器中会出现一个名为“USB串行设备”的串口名称,这个就是开发板上的AT-Link-EZ所生成的VCP虚拟串口。

打开Artery_ICP_Programmer工具,点击连接,连接成功后会显示当前连接的芯片型号,AT-Link-EZ固件号等信息,选择合适的读取大小读取存储器数据,当出现一连串的0xFF湿就已经读取完所有字节了。可以导出.bin文件保存。





5.功耗测试
5.1 PWC简介
电源控制的功能主要包含以下内容
  • 供电方案,包括VDD、VDDA的供电
  • 电源域,由VDD/VDDA域,1.2V域组成
  • 上电低电压复位,由上电复位和低电压复位组成
  • 电压监测器,监测供电电压与设定临界值关系
  • 电压调节器,电压调节器的几个工作状态
  • 省电模式,包括睡眠模式、深度睡眠模式、待机模式
5.2省电模式特性
5.2.1省电模式电流消耗
省电模式下的电流消耗会被明显降低, Datasheet都有经过详细测试后的数据记录。如下表示例记录:
(1)  典型值是在TA = 25 °C下测试得到;
(2)  由综合评估得出,不在生产中测试;
(3)  睡眠模式下的电流消耗与运行模式间差异不是特别大,本表未做罗列,具体请参考Datasheet;
(4)  不同型号产品对应的特性参数存在区别,本表摘自AT32L021xx,其他型号请以实际Datasheet为准。

5.2.2省电模式唤醒时间
省电模式下的唤醒均需要等待及稳定时间, Datasheet都有经过详细测试后的数据记录。如下表记录:
(1)  不同型号产品对应的特性参数存在区别,本表摘自AT32L021xx,其他型号请以实际Datasheet为准。


5.3 PWC省电模式解析
MCU的工作不可避免的会产生一定的功耗,对于应用实际而言,降低功耗的考量十分重要。结合MCU特性及应用条件,以下罗列部分典型降低功耗的方法。
  • CPU运行状态下,适当降低系统时钟;
  • CPU运行状态下,关闭AHB和APB总线上未被使用的外设时钟;
  • CPU无需运行时,MCU进入省电模式(睡眠模式、深度睡眠模式、待机模式)。
5.3.1 睡眠模式
在睡眠模式下,CPU时钟关闭,其他时钟保持正常工作,电压调节器正常工作,所有的I/O管脚都保持它们在运行模式时的状态,LDO以正常功耗模式提供1.2V电源(CPU内核、内存和内嵌外设)。
Cortex®-M0+内核设计控制位SLEEPONEXIT,其功能如下:
结合SLEEPONEXIT位的设定,MCU支持两种睡眠机制:
  • SLEEPONEXIT = 0,执行睡眠指令,此时可立即进入睡眠模式;
  • SLEEPONEXIT = 1,执行睡眠指令,此时每当系统从最低优先级的中断处理程序中退出时,会立即进入睡眠模式。
睡眠模式进入及退出
WFI
进入条件:SLEEPDEEP = 0,再执行WFI命令行;
唤醒条件:任意外设中断(该外设的中断使能位及NVIC使能位均被使能)的响应;

WFE
进入条件:SLEEPDEEP = 0,再执行WFE命令行;
唤醒条件:
  • 任意外设中断(该外设的中断使能位及NVIC使能位均被使能)的响应;
  • 任意EXINT线(该EXINT线必须配置为事件模式)上产生的唤醒事件;
  • SEVONPEND = 1,任意外设中断(该外设的NVIC使能位未使能)的产生。在进入睡眠之前要确保外设中断挂起位和NVIC通道挂起位均未处于置位状态。且此方式唤醒后,软件需清除外设中断挂起位和NVIC通道挂起位。
其中, SLEEPDEEP、SEVONPEND均为Cortex®-M0+内设计核控制位。其功能介绍如下(详细的说明可参考Cortex®-M0+手册):
睡眠模式的进入由独立的软件接口实现,其软件实例如下:
<div style="text-align: left;"> /* enter sleep mode */</div><div style="text-align: left;">pwc_sleep_mode_enter(PWC_SLEEP_ENTER_WFI);</div>
注意:
1) WFE进入的睡眠模式唤醒所需的时间最短,因为没有时间损失在中断的进入或退出上;
2) SLEEPONEXIT规则可结合WFI或WFE使用,但应用设计时需注意其与唤醒条件的配合;
3) 应用设计时不开PWC接口时钟条件下,执行睡眠模式进入函数同样会实现CPU暂停并等待中断或事件的效果,只是其功耗不会被明显降低。


案例 USART1接收中断唤醒PWC睡眠模式
本例将演示PWC睡眠模式的使用。其中,唤醒源使用USART1的接收中断。
资源准备
1) 硬件环境 对应产品型号的AT-START BOARD
2) 软件环境 project\at_start_l021\examples\pwc\sleep_usart1

1) 配置流程
  • 开启PWC时钟
  • 初始化USART1并使能接收数据缓冲器满中断
  • 使能USART1中断的NVIC中断
  • 使能USART1
  • 循环执行进睡眠模式命令并等待唤醒

2) 代码介绍
  • USART1配置函数代码
void usart1_config(uint32_t baudrate) 
{
  gpio_init_type gpio_init_struct;

  /* enable the uart1 and gpio clock */
  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);

  /* configure the uart1 tx pin */
  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_pull           = GPIO_PULL_NONE;
  gpio_init_struct.gpio_pins           = GPIO_PINS_9;
  gpio_init(GPIOA, &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_MUX;
  gpio_init_struct.gpio_pull           = GPIO_PULL_UP;
  gpio_init_struct.gpio_pins           = GPIO_PINS_10;
  • 中断服务函数代码
void USART1_IRQHandler(void) 
{
  if(usart_flag_get(USART1, USART_RDBF_FLAG) != RESET)
  {
    /* clear rdbf flag */
    usart1_index = usart_data_receive(USART1);

    /* toggle led */
    at32_led_toggle(LED4);
  }
}
  • main函数代码
int main(void) 
{
  __IO uint32_t index = 0;
  __IO uint32_t systick_index = 0;

  /* congfig the system clock */
  system_clock_config();

  /* init at start board */
  at32_board_init();

  /* turn on the led light */
  at32_led_on(LED2);
  at32_led_on(LED3);
  at32_led_on(LED4);
/* enable pwc clock */
  crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);

  /* config usart1 */
  usart1_config(115200);

  printf("exit sleep mode by usart1 rdbf interrupt \r\n");

  while(1)
  {
    at32_led_off(LED2);
    at32_led_off(LED3);
    printf("now enter sleep mode \r\n");

    /* save systick register configuration */
    systick_index = SysTick->CTRL;
    systick_index &= ~((uint32_t)0xFFFFFFFE);

    /* disable systick */
    SysTick->CTRL &= (uint32_t)0xFFFFFFFE;

    /* enter sleep mode */
    pwc_sleep_mode_enter(PWC_SLEEP_ENTER_WFI);

    /* restore systick register configuration */
    SysTick->CTRL |= systick_index;

    /* wake up from sleep mode */
    printf("now exit sleep mode by usart1 rdbf interrupt \r\n");

    at32_led_on(LED2);
    delay_ms(300);
  }
}

实验效果
可通过AT-START BOARD上的LED翻转查看实现效果。
LED2亮:MCU处于运行模式;
LED2灭:MCU处于睡眠模式;
LED4状态翻转: USART1接收数据缓冲器满终端发生并唤醒了睡眠模式。
也可通过USART1的串口打印查看实验效果,如下:  
下面左侧图片是本例程MCU处于运行模式的电流大小,运行模式为7.2mA。右侧图片是MCU处于睡眠模式的电流大小,睡眠模式为4.3mA。(测试地点为成都,环境室温,VDD=1.8V)



5.3.2  深度睡眠模式
在深度睡眠模式下,所有1.2V时钟关闭,HICK和HEXT振荡器都被关闭,电压调节器以正常工作或低功耗工作状态给1.2V域供电,所有I/O管脚都保持它们在运行模式时的状态,SRAM和寄存器内容保持。 深度睡眠模式可与LDO的正常模式、低功耗模式配合使用以进一步节省功耗。
深度睡眠模式进入及退出
WFI
进入条件:SLEEPDEEP = 1,LPSEL = 0,再执行WFI命令行;
唤醒条件:任意EXINT线(该EXINT线需配置为中断模式且NVIC使能位被使能)上的中断响应。

WFE
进入条件:SLEEPDEEP = 1,LPSEL = 0,再执行WFE命令行;
唤醒条件:任意EXINT线(该EXINT线需配置为事件模式)上产生的唤醒事件。
其中, SLEEPDEEP为Cortex®-M0+内设计核控制位。 系统从深度睡眠模式退出时,HICK RC振荡器被自动开启并在稳定后被选为系统时钟。
/* congfig the voltage regulator mode */ 
pwc_voltage_regulate_set(PWC_REGULATOR_LOW_POWER);
/* enter deep sleep mode */
pwc_deep_sleep_mode_enter(PWC_DEEP_SLEEP_ENTER_WFI);
注意:
1) 退出深度睡眠模式后,HICK RC振荡器被选为系统时钟,软件需根据需求对系统时钟重新设定;
2) 退出深度睡眠模式时,LDO会保持正常模式,因此若进深睡眠前配置为了低功耗模式的话,LDO的模式切换需要一定耗时,从而会增加额外的唤醒时间。

案例 USART接收数据唤醒PWC深度睡眠模式
本例将演示PWC深度睡眠模式的使用。其中,唤醒源使用USART1接收数据缓冲器满中断。
资源准备
1) 硬件环境: 对应产品型号的AT-START BOARD
2) 软件环境 project\at_start_l021\examples\pwc\deepsleep_usart1

软件设计
1) 配置流程
  • 开启PWC时钟
  • 执行USART1基础配置并使能接收数据缓冲器满中断
  • 开启deepsleep模式下的USART使能位
  • 选择低功耗唤醒方式为RDBF
  • 使能USART的低功耗唤醒中断
  • 配置EXINT线25为中断模式并使能
  • 等待USART接收器空闲
  • 设定电压调节器输出电压为1.0V
  • 执行进深度睡眠模式命令并等待唤醒
  • 唤醒后设定电压调节器输出电压为1.2V
  • 重新进行系统时钟的恢复设定
  • 从“等待USART接收器空闲”开始循环,实现深度睡眠模式的循环唤醒

2) 代码介绍
  • USART1基础配置函数代码
void usart1_config(uint32_t baudrate) 
{
gpio_init_type gpio_init_struct;
/* allow access to ertc */
pwc_battery_powered_domain_access(TRUE);
/* reset ertc domain */
crm_battery_powered_domain_reset(TRUE);
crm_battery_powered_domain_reset(FALSE);
/* enable the lext osc */
crm_clock_source_enable(CRM_CLOCK_SOURCE_LEXT, TRUE);
/* wait till lext is ready */
  while(crm_flag_get(CRM_LEXT_STABLE_FLAG) == RESET);
   
  crm_usart_clock_select(CRM_USART1, CRM_USART_CLOCK_SOURCE_LEXT);

  /* enable the uart1 and gpio clock */
  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);

  /* configure the uart1 tx pin */
  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_pull           = GPIO_PULL_UP;//GPIO_PULL_NONE;
  gpio_init_struct.gpio_pins           = GPIO_PINS_9;
  gpio_init(GPIOA, &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_MUX;
  gpio_init_struct.gpio_pull           = GPIO_PULL_UP;
  gpio_init_struct.gpio_pins           = GPIO_PINS_10;
  gpio_init(GPIOA, &gpio_init_struct);

  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE9, GPIO_MUX_1);
  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE10, GPIO_MUX_1);

  /* configure uart param */
  nvic_irq_enable(USART1_IRQn, 0, 0);

  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_hardware_flow_control_set(USART1,USART_HARDWARE_FLOW_NONE);
  usart_interrupt_enable(USART1, USART_RDBF_INT, TRUE);
   
  usart_enable(USART1, TRUE);
   
    /* polling usart initialisation */
  while((!(usart_flag_get(USART1, USART_TXON_FLAG))) || (!(usart_flag_get(USART1,
USART_RXON_FLAG))))
  {  
  }
}
  • 系统时钟恢复函数代码
void system_clock_recover(void) 
{
  /* enable external high-speed crystal oscillator - hext */
  crm_clock_source_enable(CRM_CLOCK_SOURCE_HEXT, TRUE);

  /* wait till hext is ready */
  while(crm_hext_stable_wait() == ERROR);

  /* enable pll */
  crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE);

  /* wait till pll is ready */
  while(crm_flag_get(CRM_PLL_STABLE_FLAG) == RESET);

  /* select pll as system clock source */
  crm_sysclk_switch(CRM_SCLK_PLL);

  /* wait till pll is used as system clock source */
  while(crm_sysclk_switch_status_get() != CRM_SCLK_PLL);
}
  • 中断服务函数代码
void USART1_IRQHandler (void) 
{
if(usart_flag_get(USART1, USART_RDBF_FLAG) != RESET)
{
/* clear rdbf flag */
usart1_index = usart_data_receive(USART1);
/* toggle led */
at32_led_toggle(LED4);
}
if(usart_flag_get(USART1, USART_LPWUF_FLAG) != RESET)
{
usart_flag_clear(USART1, USART_LPWUF_FLAG);
}
if(exint_flag_get(EXINT_LINE_25) != RESET)
{
exint_flag_clear(EXINT_LINE_25);
}
}
  • main函数代码
int main(void) 
{
__IO uint32_t index = 0;
__IO uint32_t systick_index = 0;
/* enable pwc clock */
crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
/* congfig the voltage regulator mode.only used with deep sleep mode */
pwc_voltage_regulate_set(PWC_REGULATOR_LOW_POWER);
/* congfig the system clock */
system_clock_config();
/* init at start board */
at32_board_init();
/* turn on the led light */
at32_led_on(LED2);
at32_led_on(LED3);
at32_led_on(LED4);
/* config usart1 */
usart1_config(2400);
usart1_wakeup_config();

  printf("exit deepsleep mode by usart1 rdbf interrupt \r\n");
  while(1)
  {
    at32_led_off(LED2);
    printf("now enter deepsleep mode \r\n");
     
    /* make sure that no usart receiver is ongoing */  
    while(usart_flag_get(USART1, USART_OCCUPY_FLAG) == SET)
    {
    }
     
    /* select system clock source as hick before ldo set */
    crm_sysclk_switch(CRM_SCLK_HICK);

    /* wait till hick is used as system clock source */
    while(crm_sysclk_switch_status_get() != CRM_SCLK_HICK)
    {
    }
     
    /* reduce ldo before enter deepsleep mode */
    pwc_ldo_output_voltage_set(PWC_LDO_OUTPUT_1V0);

    while(usart_flag_get(USART1, USART_TDC_FLAG) == RESET)
    {
    }
     
    /* enter deep sleep mode */
    pwc_deep_sleep_mode_enter(PWC_DEEP_SLEEP_ENTER_WFI);

    /* turn on the led light */
    at32_led_on(LED2);
     
    /* resume ldo before system clock source enhance */
    pwc_ldo_output_voltage_set(PWC_LDO_OUTPUT_1V2);
     
    /* wake up from deep sleep mode, congfig the system clock */
    system_clock_recover();
     
    /* wake up from sleep mode */
    printf("\r\nnow exit deepsleep mode by usart1 rdbf interrupt \r\n");
    printf("usart1_rdne_data = 0x%x\r\n", usart1_index);
    delay_ms(300);
  }
}

实验效果
可通过AT-START BOARD上的LED翻转查看实现效果。
LED2亮:MCU处于运行模式;
LED2灭:MCU处于深度睡眠模式;
LED4状态翻转: USART1接收缓冲器满中断发生并唤醒了深度睡眠模式。
也可通过USART1的串口打印查看实验效果,如下:

下面左侧图片是本例程MCU处于运行模式的电流大小,运行模式为6.6mA。右侧图片是MCU处于深度睡眠模式的电流大小,睡眠模式为1.6mA。(测试地点为成都,环境室温,VDD=1.8V     注:LDO未处于低功耗模式,HICK和HEXT未关闭,WDT已关闭)。所以测试结果会比手册中的典型值高。



5.3.3待机模式
待机模式可最大限度的降低系统功耗,在该模式下,电压调节器关闭,只有电池供电的寄存器和待机电路维持供电,其他的1.2V供电区域,PLL、HICK和HEXT振荡器都被断电。寄存器和SRAM中的内容也会丢失。 在待机模式下,除了复位管脚、被设置为防侵入或校准输出时的TAMPER管脚和被使能的唤醒管脚之外,所有的I/O管脚处于高阻态。
待机模式进入及退出
进入条件:SLEEPDEEP = 1,LPSEL = 1,再执行WFI/WFE命令行;
退出条件:
  • WKUP管脚的上升沿;发生唤醒时会置位SEF、SWEF标志
  • NRST管脚上外部复位;发生复位时会置位SEF、NRSTF标志
  • WDT复位;发生复位时会置位SEF、WDTRSTF、NRSTF标志
  • 实时时钟事件的上升沿;发生唤醒时会置位SEF、SWEF、及实时时钟事件对应标志
实时时钟事件为ERTC闹钟事件、ERTC入侵事件、ERTC时间戳、ERTC周期性自动唤醒事件。
实时时钟在部分型号为RTC,部分型号为ERTC,部分ERTC型号不支持周期性自动唤醒,部分型号支持双闹钟。且部分型号具备多个WKUP管脚等,这些差异部分请以实际芯片手册为准。
/* enter standby mode */ 
pwc_standby_mode_enter();
/* enable wakeup pin */
pwc_wakeup_pin_enable(PWC_WAKEUP_PIN_1, TRUE);
注意:
1) SWEF标志为待机唤醒事件标志,其处于置位状态下执行进入待机模式命令,会立即产生复位。故在进入待机模式前,软件需确保SWEF标志已被清除;
2) 部分型号具备多个WKUP管脚,具体请以实际芯片手册为准
3) 实时时钟在部分型号为RTC,部分型号为ERTC,具体请以实际芯片手册为准;
4) 部分ERTC型号不支持周期性自动唤醒,部分型号支持双闹钟,具体请以实际芯片手册为准。

案例 PWC待机模式
本例将演示PWC待机模式的使用。其中,唤醒源使用WKUPx管脚上升沿。
资源准备
1) 硬件环境: 对应产品型号的AT-START BOARD USER_KEY1——PA0
2) 软件环境 project\at_start_l021\examples\ pwc\standby_wakeup_pin

软件设计
1) 配置流程
  • 开启PWC时钟
  • 检测进入待机模式标志并清除
  • 检测待机唤醒事件标志并清除
  • 使能WKUP1引脚
  • 执行进待机模式命令并等待唤醒

2) 代码介绍
  • main函数代码
int main(void)
{
__IO uint32_t index = 0;
/* congfig the system clock */
system_clock_config();
/* init at start board */
at32_board_init();
/* turn on the led light */
at32_led_off(LED2);
at32_led_off(LED3);
at32_led_off(LED4);

/* enable pwc clock */
crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);

if(pwc_flag_get(PWC_STANDBY_FLAG) != RESET)
{
/* wakeup from standby */
  pwc_flag_clear(PWC_STANDBY_FLAG);
at32_led_on(LED2);
}

if(pwc_flag_get(PWC_WAKEUP_FLAG) != RESET)
{
/* wakeup event occurs */
pwc_flag_clear(PWC_WAKEUP_FLAG);
at32_led_on(LED3);
}

at32_led_on(LED4);

/*delay to check led status*/
delay_ms(1000);
delay_ms(1000);

/* enable wakeup pin1 */
pwc_wakeup_pin_enable(PWC_WAKEUP_PIN_1, TRUE);

/* enter standby mode */
pwc_standby_mode_enter();
while(1)
{
}
}
实验效果
可通过AT-START BOARD上的USER_KEY来唤醒,LED翻转查看实现效果。
LED4亮:MCU处于运行模式;
LED4灭:MCU处于待机模式;
MCU运行状态下的LED2: 亮表示进入待机模式标志置位,反之未置位;
MCU运行状态下的LED3: 亮表示待机唤醒事件标志置位,反之未置位。

下面左侧图片是本例程MCU处于运行模式的电流大小,运行模式为7.0mA。右侧图片是MCU处于待机模式的电流大小,睡眠模式为0.000mA。(测试地点为成都,环境室温,VDD=1.8V),因万用表精度影响所以没有显示出有效数值,但是可以判断出待机模式电流小于1uA,与手册中相符。


6.驱动移植

  单片机可供移植的协议和驱动非常多,每种协议下又有很多的模块和设备可以移植。这里以最常用的I2C协议为例,使用0.96寸OLED进行驱动移植。0.96寸OLED可以使用I2C进行通信。因为I2C总线可以挂在多设备,通过设备地址识别从机,所以不占用硬件资源,相对于串口调试来说节省硬件资源,特别是在硬件资源没有富余的情况下更有优势,同时也不干扰总线上其他设备正常工作。
  使用软件模拟I2C的方式可以不受引脚影响,在非高速情况下,一个好的软件模拟驱动协议比硬件协议更稳定易用,哪怕换了单片机也能很快移植,同时更易排查问题点。这里使用软件模拟I2C的方式移植0.96寸OLED驱动协议,虽然例子很简单,没有复杂的显示。但是驱动部分移植成功了,上层的使用都是不变的,这里就不对复杂的显示展开,仅作驱动移植介绍:
  这个是江协科技的0.96寸OLED驱动部分:
oled.c文件
#include "stm32f10x.h"
#include "OLED_Font.h"

/*引脚配置*/
#define OLED_W_SCL(x)                GPIO_WriteBit(GPIOB, GPIO_Pin_6, (BitAction)(x))
#define OLED_W_SDA(x)                GPIO_WriteBit(GPIOB, GPIO_Pin_7, (BitAction)(x))

/*引脚初始化*/
void OLED_I2C_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        
        GPIO_InitTypeDef GPIO_InitStructure;
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
         GPIO_Init(GPIOB, &GPIO_InitStructure);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
         GPIO_Init(GPIOB, &GPIO_InitStructure);
        
        OLED_W_SCL(1);
        OLED_W_SDA(1);
}

/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  I2C开始
  * @param  无
  * @retval 无
  */
void OLED_I2C_Start(void)
{
        OLED_W_SDA(1);
        OLED_W_SCL(1);
        OLED_W_SDA(0);
        OLED_W_SCL(0);
}

/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  I2C停止
  * @param  无
  * @retval 无
  */
void OLED_I2C_Stop(void)
{
        OLED_W_SDA(0);
        OLED_W_SCL(1);
        OLED_W_SDA(1);
}

/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的一个字节
  * @retval 无
  */
void OLED_I2C_SendByte(uint8_t Byte)
{
        uint8_t i;
        for (i = 0; i < 8; i++)
        {
                OLED_W_SDA(Byte & (0x80 >> i));
                OLED_W_SCL(1);
                OLED_W_SCL(0);
        }
        OLED_W_SCL(1);        //额外的一个时钟,不处理应答信号
        OLED_W_SCL(0);
}

/**
  * @brief  OLED写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void OLED_WriteCommand(uint8_t Command)
{
        OLED_I2C_Start();
        OLED_I2C_SendByte(0x78);                //从机地址
        OLED_I2C_SendByte(0x00);                //写命令
        OLED_I2C_SendByte(Command);
        OLED_I2C_Stop();
}

/**
  * @brief  OLED写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void OLED_WriteData(uint8_t Data)
{
        OLED_I2C_Start();
        OLED_I2C_SendByte(0x78);                //从机地址
        OLED_I2C_SendByte(0x40);                //写数据
        OLED_I2C_SendByte(Data);
        OLED_I2C_Stop();
}

/**
  * @brief  OLED设置光标位置
  * @param  Y 以左上角为原点,向下方向的坐标,范围:0~7
  * @param  X 以左上角为原点,向右方向的坐标,范围:0~127
  * @retval 无
  */
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
        OLED_WriteCommand(0xB0 | Y);                                        //设置Y位置
        OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));        //设置X位置高4位
        OLED_WriteCommand(0x00 | (X & 0x0F));                        //设置X位置低4位
}

/**
  * @brief  OLED清屏
  * @param  无
  * @retval 无
  */
void OLED_Clear(void)
{  
        uint8_t i, j;
        for (j = 0; j < 8; j++)
        {
                OLED_SetCursor(j, 0);
                for(i = 0; i < 128; i++)
                {
                        OLED_WriteData(0x00);
                }
        }
}

/**
  * @brief  OLED显示一个字符
  * @param  Line 行位置,范围:1~4
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的一个字符,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{              
        uint8_t i;
        OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);                //设置光标位置在上半部分
        for (i = 0; i < 8; i++)
        {
                OLED_WriteData(OLED_F8x16[Char - ' '][i]);                        //显示上半部分内容
        }
        OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);        //设置光标位置在下半部分
        for (i = 0; i < 8; i++)
        {
                OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);                //显示下半部分内容
        }
}

/**
  * @brief  OLED显示字符串
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
        uint8_t i;
        for (i = 0; String[i] != '\0'; i++)
        {
                OLED_ShowChar(Line, Column + i, String[i]);
        }
}

/**
  * @brief  OLED次方函数
  * @retval 返回值等于X的Y次方
  */
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
        uint32_t Result = 1;
        while (Y--)
        {
                Result *= X;
        }
        return Result;
}

/**
  * @brief  OLED显示数字(十进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~4294967295
  * @param  Length 要显示数字的长度,范围:1~10
  * @retval 无
  */
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
        uint8_t i;
        for (i = 0; i < Length; i++)                                                        
        {
                OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
        }
}

/**
  * @brief  OLED显示数字(十进制,带符号数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-2147483648~2147483647
  * @param  Length 要显示数字的长度,范围:1~10
  * @retval 无
  */
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
        uint8_t i;
        uint32_t Number1;
        if (Number >= 0)
        {
                OLED_ShowChar(Line, Column, '+');
                Number1 = Number;
        }
        else
        {
                OLED_ShowChar(Line, Column, '-');
                Number1 = -Number;
        }
        for (i = 0; i < Length; i++)                                                        
        {
                OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
        }
}

/**
  * @brief  OLED显示数字(十六进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFFFFFF
  * @param  Length 要显示数字的长度,范围:1~8
  * @retval 无
  */
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
        uint8_t i, SingleNumber;
        for (i = 0; i < Length; i++)                                                        
        {
                SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
                if (SingleNumber < 10)
                {
                        OLED_ShowChar(Line, Column + i, SingleNumber + '0');
                }
                else
                {
                        OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
                }
        }
}

/**
  * @brief  OLED显示数字(二进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
        uint8_t i;
        for (i = 0; i < Length; i++)                                                        
        {
                OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
        }
}

/**
  * @brief  OLED初始化
  * @param  无
  * @retval 无
  */
void OLED_Init(void)
{
        uint32_t i, j;
        
        for (i = 0; i < 1000; i++)                        //上电延时
        {
                for (j = 0; j < 1000; j++);
        }
        
        OLED_I2C_Init();                        //端口初始化
        
        OLED_WriteCommand(0xAE);        //关闭显示
        
        OLED_WriteCommand(0xD5);        //设置显示时钟分频比/振荡器频率
        OLED_WriteCommand(0x80);
        
        OLED_WriteCommand(0xA8);        //设置多路复用率
        OLED_WriteCommand(0x3F);
        
        OLED_WriteCommand(0xD3);        //设置显示偏移
        OLED_WriteCommand(0x00);
        
        OLED_WriteCommand(0x40);        //设置显示开始行
        
        OLED_WriteCommand(0xA1);        //设置左右方向,0xA1正常 0xA0左右反置
        
        OLED_WriteCommand(0xC8);        //设置上下方向,0xC8正常 0xC0上下反置

        OLED_WriteCommand(0xDA);        //设置COM引脚硬件配置
        OLED_WriteCommand(0x12);
        
        OLED_WriteCommand(0x81);        //设置对比度控制
        OLED_WriteCommand(0xCF);

        OLED_WriteCommand(0xD9);        //设置预充电周期
        OLED_WriteCommand(0xF1);

        OLED_WriteCommand(0xDB);        //设置VCOMH取消选择级别
        OLED_WriteCommand(0x30);

        OLED_WriteCommand(0xA4);        //设置整个显示打开/关闭

        OLED_WriteCommand(0xA6);        //设置正常/倒转显示

        OLED_WriteCommand(0x8D);        //设置充电泵
        OLED_WriteCommand(0x14);

        OLED_WriteCommand(0xAF);        //开启显示
               
        OLED_Clear();                                //OLED清屏
}
oled.h文件
#ifndef __OLED_H
#define __OLED_H

void OLED_Init(void);
void OLED_Clear(void);
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);

#endif
oled_font.h文件
#ifndef __OLED_FONT_H
#define __OLED_FONT_H

/*OLED字模库,宽8像素,高16像素*/
const uint8_t OLED_F8x16[][16]=
{
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//  0
        
        0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
        
        0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
        
        0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,
        0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
        
        0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,
        0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
        
        0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,
        0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
        
        0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,
        0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
        
        0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
        
        0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,
        0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
        
        0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,
        0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
        
        0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,
        0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
        
        0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,
        0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
        
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
        
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
        
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
        
        0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,
        0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
        
        0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
        0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
        
        0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,
        0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
        
        0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,
        0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
        
        0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,
        0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
        
        0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,
        0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
        
        0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,
        0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
        
        0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,
        0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
        
        0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,
        0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
        
        0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,
        0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
        
        0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
        0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
        
        0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,
        0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
        
        0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
        0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
        
        0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,
        0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
        
        0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,
        0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
        
        0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,
        0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
        
        0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,
        0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
        
        0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,
        0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//[url=home.php?mod=space&uid=72445]@[/url] 32
        
        0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,
        0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
        
        0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,
        0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
        
        0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,
        0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
        
        0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,
        0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
        
        0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
        0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
        
        0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
        0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
        
        0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,
        0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
        
        0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
        0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
        
        0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,
        0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
        
        0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,
        0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
        
        0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,
        0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
        
        0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,
        0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
        
        0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,
        0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
        
        0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,
        0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
        
        0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
        0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
        
        0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,
        0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
        
        0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
        0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
        
        0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,
        0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
        
        0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,
        0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
        
        0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,
        0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
        
        0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
        0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
        
        0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,
        0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
        
        0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,
        0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
        
        0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,
        0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
        
        0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,
        0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
        
        0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,
        0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
        
        0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,
        0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
        
        0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
        
        0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,
        0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
        
        0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
        
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
        
        0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
        
        0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
        0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
        
        0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,
        0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
        
        0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,
        0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
        
        0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,
        0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
        
        0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
        0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
        
        0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,
        0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
        
        0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
        0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
        
        0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,
        0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
        
        0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,
        0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
        
        0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,
        0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
        
        0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,
        0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
        
        0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,
        0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
        
        0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
        0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
        
        0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,
        0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
        
        0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
        0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
        
        0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,
        0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
        
        0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,
        0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
        
        0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
        0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
        
        0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
        0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
        
        0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,
        0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
        
        0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,
        0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
        
        0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
        0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
        
        0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,
        0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
        
        0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
        0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
        
        0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
        0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
        
        0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
        0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
        
        0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,
        0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
        
        0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
        
        0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,
        0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
        
        0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};

#endif
做移植时这里只用对oled.c文件的引脚号和读写函数进行修改。如果使用同样的引脚模拟I2C的话就只用修改读写函数。一般不同的芯片厂商的库函数不同,当人也可以自己封装一层调用。这里修改后的oled.c文件如下
移植后的oled.c文件
//#include "stm32f10x.h"
#include "at32l021_board.h"
#include "OLED_Font.h"
#include "at32l021_clock.h"
/*引脚配置*/


/*引脚初始化*/
void OLED_I2C_Init(void)
{
        
        
        (GPIOB->scr = GPIO_PINS_8);
        (GPIOB->scr = GPIO_PINS_9);
}

/**
  * @brief  I2C开始
  * @param  无
  * @retval 无
  */
void OLED_I2C_Start(void)
{
        (GPIOB->scr = GPIO_PINS_9);
        (GPIOB->scr = GPIO_PINS_8);
        (GPIOB->scr= GPIO_PINS_9);
        (GPIOB->clr= GPIO_PINS_9);
}

/**
  * @brief  I2C停止
  * @param  无
  * @retval 无
  */
void OLED_I2C_Stop(void)
{
        (GPIOB->scr= GPIO_PINS_9);
        (GPIOB->scr = GPIO_PINS_8);
        (GPIOB->scr = GPIO_PINS_9);
}

/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的一个字节
  * @retval 无
  */
void OLED_I2C_SendByte(uint8_t Byte)
{
        uint8_t i;
        for (i = 0; i < 8; i++)
        {
                //OLED_W_SDA(Byte & (0x80 >> i));
                if(Byte & (0x80 >> i))                GPIOB->scr = GPIO_PINS_9;
                else                                                                                        GPIOB->clr = GPIO_PINS_9;
                (GPIOB->scr = GPIO_PINS_8);
                (GPIOB->clr= GPIO_PINS_9);
        }
        (GPIOB->scr = GPIO_PINS_8);        //额外的一个时钟,不处理应答信号
        (GPIOB->clr= GPIO_PINS_9);
}

/**
  * @brief  OLED写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void OLED_WriteCommand(uint8_t Command)
{
        OLED_I2C_Start();
        OLED_I2C_SendByte(0x78);                //从机地址
        OLED_I2C_SendByte(0x00);                //写命令
        OLED_I2C_SendByte(Command);
        OLED_I2C_Stop();
}

/**
  * @brief  OLED写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void OLED_WriteData(uint8_t Data)
{
        OLED_I2C_Start();
        OLED_I2C_SendByte(0x78);                //从机地址
        OLED_I2C_SendByte(0x40);                //写数据
        OLED_I2C_SendByte(Data);
        OLED_I2C_Stop();
}

/**
  * @brief  OLED设置光标位置
  * @param  Y 以左上角为原点,向下方向的坐标,范围:0~7
  * @param  X 以左上角为原点,向右方向的坐标,范围:0~127
  * @retval 无
  */
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
        OLED_WriteCommand(0xB0 | Y);                                        //设置Y位置
        OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4));        //设置X位置高4位
        OLED_WriteCommand(0x00 | (X & 0x0F));                        //设置X位置低4位
}

/**
  * @brief  OLED清屏
  * @param  无
  * @retval 无
  */
void OLED_Clear(void)
{  
        uint8_t i, j;
        for (j = 0; j < 8; j++)
        {
                OLED_SetCursor(j, 0);
                for(i = 0; i < 128; i++)
                {
                        OLED_WriteData(0x00);
                }
        }
}

/**
  * @brief  OLED显示一个字符
  * @param  Line 行位置,范围:1~4
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的一个字符,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{              
        uint8_t i;
        OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);                //设置光标位置在上半部分
        for (i = 0; i < 8; i++)
        {
                OLED_WriteData(OLED_F8x16[Char - ' '][i]);                        //显示上半部分内容
        }
        OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);        //设置光标位置在下半部分
        for (i = 0; i < 8; i++)
        {
                OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);                //显示下半部分内容
        }
}

/**
  * @brief  OLED显示字符串
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串,范围:ASCII可见字符
  * @retval 无
  */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
        uint8_t i;
        for (i = 0; String[i] != '\0'; i++)
        {
                OLED_ShowChar(Line, Column + i, String[i]);
        }
}

/**
  * @brief  OLED次方函数
  * @retval 返回值等于X的Y次方
  */
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
        uint32_t Result = 1;
        while (Y--)
        {
                Result *= X;
        }
        return Result;
}

/**
  * @brief  OLED显示数字(十进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~4294967295
  * @param  Length 要显示数字的长度,范围:1~10
  * @retval 无
  */
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
        uint8_t i;
        for (i = 0; i < Length; i++)                                                        
        {
                OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
        }
}

/**
  * @brief  OLED显示数字(十进制,带符号数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-2147483648~2147483647
  * @param  Length 要显示数字的长度,范围:1~10
  * @retval 无
  */
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
        uint8_t i;
        uint32_t Number1;
        if (Number >= 0)
        {
                OLED_ShowChar(Line, Column, '+');
                Number1 = Number;
        }
        else
        {
                OLED_ShowChar(Line, Column, '-');
                Number1 = -Number;
        }
        for (i = 0; i < Length; i++)                                                        
        {
                OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
        }
}

/**
  * @brief  OLED显示数字(十六进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFFFFFF
  * @param  Length 要显示数字的长度,范围:1~8
  * @retval 无
  */
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
        uint8_t i, SingleNumber;
        for (i = 0; i < Length; i++)                                                        
        {
                SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
                if (SingleNumber < 10)
                {
                        OLED_ShowChar(Line, Column + i, SingleNumber + '0');
                }
                else
                {
                        OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
                }
        }
}

/**
  * @brief  OLED显示数字(二进制,正数)
  * @param  Line 起始行位置,范围:1~4
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
        uint8_t i;
        for (i = 0; i < Length; i++)                                                        
        {
                OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
        }
}

/**
  * @brief  OLED初始化
  * @param  无
  * @retval 无
  */
void OLED_Init(void)
{
        uint32_t i, j;
        
        for (i = 0; i < 1000; i++)                        //上电延时
        {
                for (j = 0; j < 1000; j++);
        }
        
        OLED_I2C_Init();                        //端口初始化
        
        OLED_WriteCommand(0xAE);        //关闭显示
        
        OLED_WriteCommand(0xD5);        //设置显示时钟分频比/振荡器频率
        OLED_WriteCommand(0x80);
        
        OLED_WriteCommand(0xA8);        //设置多路复用率
        OLED_WriteCommand(0x3F);
        
        OLED_WriteCommand(0xD3);        //设置显示偏移
        OLED_WriteCommand(0x00);
        
        OLED_WriteCommand(0x40);        //设置显示开始行
        
        OLED_WriteCommand(0xA1);        //设置左右方向,0xA1正常 0xA0左右反置
        
        OLED_WriteCommand(0xC8);        //设置上下方向,0xC8正常 0xC0上下反置

        OLED_WriteCommand(0xDA);        //设置COM引脚硬件配置
        OLED_WriteCommand(0x12);
        
        OLED_WriteCommand(0x81);        //设置对比度控制
        OLED_WriteCommand(0xCF);

        OLED_WriteCommand(0xD9);        //设置预充电周期
        OLED_WriteCommand(0xF1);

        OLED_WriteCommand(0xDB);        //设置VCOMH取消选择级别
        OLED_WriteCommand(0x30);

        OLED_WriteCommand(0xA4);        //设置整个显示打开/关闭

        OLED_WriteCommand(0xA6);        //设置正常/倒转显示

        OLED_WriteCommand(0x8D);        //设置充电泵
        OLED_WriteCommand(0x14);

        OLED_WriteCommand(0xAF);        //开启显示
               
        OLED_Clear();                                //OLED清屏
}
下图是移植后的OLED显示结果,只用在main.c中调用驱动即可。
main.c文件
/**
  **************************************************************************
  * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  * @brief    main program
  **************************************************************************
  *                       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 "at32l021_board.h"
#include "at32l021_clock.h"
#include "i2c_application.h"
#include "OLED.h"


/** @addtogroup AT32L021_periph_examples
  * @{
  */

void gpio_config(void)
{
  gpio_init_type gpio_init_struct;

  /* enable the gpioa clock */
  crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);

  /* set default parameter */
  gpio_default_para_init(&gpio_init_struct);

  /* configure the gpio */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_OPEN_DRAIN;
  gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  gpio_init_struct.gpio_pins = GPIO_PINS_8;
  gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  gpio_init(GPIOB, &gpio_init_struct);
        
          /* configure the gpio */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_OPEN_DRAIN;
  gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  gpio_init_struct.gpio_pins = GPIO_PINS_9;
  gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  gpio_init(GPIOB, &gpio_init_struct);
        
                  /* configure the gpio */
  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_11;
  gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  gpio_init(GPIOB, &gpio_init_struct);
}





i2c_handle_type hi2cx;

/**
  * @brief  error handler program
  * @param  i2c_status
  * @retval none
  */
void error_handler(uint32_t error_code)
{
  while(1)
  {

  }
}


/**
  * @brief  main function.
  * @param  none
  * @retval none
  */
int main(void)
{

  /* initial system clock */
  system_clock_config();

  /* at board initial */
  at32_board_init();

        gpio_config();
        
  while(1)
  {
                        OLED_Init();
        
                        OLED_ShowChar(1, 1, 'A');
                        OLED_ShowString(1, 3, "HelloWorld!");
                        OLED_ShowNum(2, 1, 12345, 5);
                        OLED_ShowSignedNum(2, 7, -66, 2);
                        OLED_ShowHexNum(3, 1, 0xAA55, 4);
                        OLED_ShowBinNum(4, 1, 0xAA55, 16);

                GPIOB->scr = GPIO_PINS_11;
    delay_ms(500);
                GPIOB->clr = GPIO_PINS_11;



  }
}


/**
  * @}
  */

/**
  * @}
  */

其余的驱动和协议都是类似的,只要有一个好的驱动,不管换了什么单片机都可以轻松移植。当然发凡事都有例外,有些特殊的问题比如多个外设不能同时使用,某些引脚只能小电流等。比如雅特力的SRAM拓展功能,这款AT32L021C8T7的SRAM是高达9KB的(在同级别芯片中算高的了),9KB的SRAM采用8+1模式,1KB是需要拓展的,虽然两块SRAM地址是连续的,但是需要通过ICP软件或者程序中进行设置实现。具体可以参考官方文档。除了官方文档非常齐全外,个人最满意的就是雅特力的技术支持群,有问必有答,很晚都在回答问题。对小微企业和个人开发者特别友好。所以在手册中那个没找到答案,可以加群:1121757020友好提问。

7.项目移植
因为本次测评开发板的另一个目的是为产品国产化选型做性能测试,所以在开发板上进行了项目的移植,并做了相关的测试。因为属于公司项目所以这里不做展开。在开发板上移植取得了成功,各参数均符合要求,特别是功耗方面。后续将做一致性测试,同时打板后再次测试性能。


8.感想与总结
  因为我司一直使用的雅特力的MCU,给我最深的印象就是:M4的核只卖M3的价。这次体验了M0+的低功耗的性能,真真正正的感觉当初没有选错,多款MCU性能都很不错,这样在软件上的时间就会省下很多,硬件上就会少踩很多坑,因为换新品牌的MCU会遇到此前不了解的问题,花费的时间相对较多。特别期待雅特力近期会发售的电机MCU,也感谢雅特力提供的机会体验这次AT32L021低功耗开发板。
  

373376746fec8efc9c.jpg (167.34 KB )

373376746fec8efc9c.jpg

166467470597e85d7.png (169.66 KB )

166467470597e85d7.png

880526747077aae1b0.png (144.74 KB )

880526747077aae1b0.png

34796747083788193.png (342.45 KB )

34796747083788193.png

28857674c5cc31d14a.jpg (229.04 KB )

28857674c5cc31d14a.jpg

10168674c5d81dcd34.jpg (158.82 KB )

10168674c5d81dcd34.jpg

28964674c5d8c4996f.jpg (158.82 KB )

28964674c5d8c4996f.jpg

47888674c6280743a4.png (89.64 KB )

47888674c6280743a4.png

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

40

帖子

0

粉丝