返回列表 发新帖我要提问本帖赏金: 30.00元(功能说明)

[活动专区] 【AT-START-L021测评】带你全方位感受国货之光

[复制链接]
 楼主| 仗剑天涯1412 发表于 2024-12-5 20:48 | 显示全部楼层 |阅读模式
本帖最后由 仗剑天涯1412 于 2024-12-5 21:16 编辑



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

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

487556746fef834ea9.png




1.生态和工具

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

5863767470058eb087.png

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

69997674701eaca076.png

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

7507674702aa08d79.png

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

3303467470362c9a4e.png

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

12974674704b038d3b.png

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

368516747058998612.png

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

75941674705eb05eb7.png

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

186156747078772f41.png

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



2.硬件资源:

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

32079674708280029b.png

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

268946747093a0d2c3.png

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

9419667470c19244d1.png

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

3183867470eba13e84.png

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

8369467470eeb556c4.png

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

1396567470e4a2f51f.png


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

5945767470f9ca88d4.png

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

631766747107ba4deb.png

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)开始轮留闪烁。

90171674713e6e5980.gif

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

73687674713f1eba4e.gif

肉眼更明显直观。再做进一步开发前,需要先了解开发板的跳线帽,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的编程和调试。
  • 启动模式选择     在启动时,通过对启动引脚配置可以选择三种启动模式中的一种。 50122674715ac6e6e3.png
  • 外部时钟源
  • 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Ω电阻

758516747171297a13.png


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

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

28167471aaf4e2ec.png




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

5.2.2省电模式唤醒时间
省电模式下的唤醒均需要等待及稳定时间, Datasheet都有经过详细测试后的数据记录。如下表记录:
13693674c68d5043b4.png
(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,其功能如下:
67148674c6119337bf.png
结合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+手册):
3673674c6202e619d.png
睡眠模式的进入由独立的软件接口实现,其软件实例如下:
  1. <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配置函数代码
  1. void usart1_config(uint32_t baudrate)
  2. {
  3.   gpio_init_type gpio_init_struct;

  4.   /* enable the uart1 and gpio clock */
  5.   crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
  6.   crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

  7.   gpio_default_para_init(&gpio_init_struct);

  8.   /* configure the uart1 tx pin */
  9.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  10.   gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  11.   gpio_init_struct.gpio_mode           = GPIO_MODE_MUX;
  12.   gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;
  13.   gpio_init_struct.gpio_pins           = GPIO_PINS_9;
  14.   gpio_init(GPIOA, &gpio_init_struct);

  15.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  16.   gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  17.   gpio_init_struct.gpio_mode           = GPIO_MODE_MUX;
  18.   gpio_init_struct.gpio_pull           = GPIO_PULL_UP;
  19.   gpio_init_struct.gpio_pins           = GPIO_PINS_10;
  • 中断服务函数代码
  1. void USART1_IRQHandler(void)
  2. {
  3.   if(usart_flag_get(USART1, USART_RDBF_FLAG) != RESET)
  4.   {
  5.     /* clear rdbf flag */
  6.     usart1_index = usart_data_receive(USART1);

  7.     /* toggle led */
  8.     at32_led_toggle(LED4);
  9.   }
  10. }
  • main函数代码
  1. int main(void)
  2. {
  3.   __IO uint32_t index = 0;
  4.   __IO uint32_t systick_index = 0;

  5.   /* congfig the system clock */
  6.   system_clock_config();

  7.   /* init at start board */
  8.   at32_board_init();

  9.   /* turn on the led light */
  10.   at32_led_on(LED2);
  11.   at32_led_on(LED3);
  12.   at32_led_on(LED4);
  13. /* enable pwc clock */
  14.   crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);

  15.   /* config usart1 */
  16.   usart1_config(115200);

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

  18.   while(1)
  19.   {
  20.     at32_led_off(LED2);
  21.     at32_led_off(LED3);
  22.     printf("now enter sleep mode \r\n");

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

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

  28.     /* enter sleep mode */
  29.     pwc_sleep_mode_enter(PWC_SLEEP_ENTER_WFI);

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

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

  34.     at32_led_on(LED2);
  35.     delay_ms(300);
  36.   }
  37. }

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



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振荡器被自动开启并在稳定后被选为系统时钟。
  1. /* congfig the voltage regulator mode */
  2. pwc_voltage_regulate_set(PWC_REGULATOR_LOW_POWER);
  3. /* enter deep sleep mode */
  4. 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基础配置函数代码
  1. void usart1_config(uint32_t baudrate)
  2. {
  3. gpio_init_type gpio_init_struct;
  4. /* allow access to ertc */
  5. pwc_battery_powered_domain_access(TRUE);
  6. /* reset ertc domain */
  7. crm_battery_powered_domain_reset(TRUE);
  8. crm_battery_powered_domain_reset(FALSE);
  9. /* enable the lext osc */
  10. crm_clock_source_enable(CRM_CLOCK_SOURCE_LEXT, TRUE);
  11. /* wait till lext is ready */
  12.   while(crm_flag_get(CRM_LEXT_STABLE_FLAG) == RESET);
  13.    
  14.   crm_usart_clock_select(CRM_USART1, CRM_USART_CLOCK_SOURCE_LEXT);

  15.   /* enable the uart1 and gpio clock */
  16.   crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
  17.   crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

  18.   gpio_default_para_init(&gpio_init_struct);

  19.   /* configure the uart1 tx pin */
  20.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  21.   gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  22.   gpio_init_struct.gpio_mode           = GPIO_MODE_MUX;
  23.   gpio_init_struct.gpio_pull           = GPIO_PULL_UP;//GPIO_PULL_NONE;
  24.   gpio_init_struct.gpio_pins           = GPIO_PINS_9;
  25.   gpio_init(GPIOA, &gpio_init_struct);

  26.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  27.   gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  28.   gpio_init_struct.gpio_mode           = GPIO_MODE_MUX;
  29.   gpio_init_struct.gpio_pull           = GPIO_PULL_UP;
  30.   gpio_init_struct.gpio_pins           = GPIO_PINS_10;
  31.   gpio_init(GPIOA, &gpio_init_struct);

  32.   gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE9, GPIO_MUX_1);
  33.   gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE10, GPIO_MUX_1);

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

  36.   usart_init(USART1, baudrate, USART_DATA_8BITS, USART_STOP_1_BIT);
  37.   usart_parity_selection_config(USART1, USART_PARITY_NONE);
  38.   usart_transmitter_enable(USART1, TRUE);
  39.   usart_receiver_enable(USART1, TRUE);
  40.   usart_hardware_flow_control_set(USART1,USART_HARDWARE_FLOW_NONE);
  41.   usart_interrupt_enable(USART1, USART_RDBF_INT, TRUE);
  42.    
  43.   usart_enable(USART1, TRUE);
  44.    
  45.     /* polling usart initialisation */
  46.   while((!(usart_flag_get(USART1, USART_TXON_FLAG))) || (!(usart_flag_get(USART1,
  47. USART_RXON_FLAG))))
  48.   {  
  49.   }
  50. }
  • 系统时钟恢复函数代码
  1. void system_clock_recover(void)
  2. {
  3.   /* enable external high-speed crystal oscillator - hext */
  4.   crm_clock_source_enable(CRM_CLOCK_SOURCE_HEXT, TRUE);

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

  7.   /* enable pll */
  8.   crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE);

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

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

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

  20.   printf("exit deepsleep mode by usart1 rdbf interrupt \r\n");
  21.   while(1)
  22.   {
  23.     at32_led_off(LED2);
  24.     printf("now enter deepsleep mode \r\n");
  25.      
  26.     /* make sure that no usart receiver is ongoing */  
  27.     while(usart_flag_get(USART1, USART_OCCUPY_FLAG) == SET)
  28.     {
  29.     }
  30.      
  31.     /* select system clock source as hick before ldo set */
  32.     crm_sysclk_switch(CRM_SCLK_HICK);

  33.     /* wait till hick is used as system clock source */
  34.     while(crm_sysclk_switch_status_get() != CRM_SCLK_HICK)
  35.     {
  36.     }
  37.      
  38.     /* reduce ldo before enter deepsleep mode */
  39.     pwc_ldo_output_voltage_set(PWC_LDO_OUTPUT_1V0);

  40.     while(usart_flag_get(USART1, USART_TDC_FLAG) == RESET)
  41.     {
  42.     }
  43.      
  44.     /* enter deep sleep mode */
  45.     pwc_deep_sleep_mode_enter(PWC_DEEP_SLEEP_ENTER_WFI);

  46.     /* turn on the led light */
  47.     at32_led_on(LED2);
  48.      
  49.     /* resume ldo before system clock source enhance */
  50.     pwc_ldo_output_voltage_set(PWC_LDO_OUTPUT_1V2);
  51.      
  52.     /* wake up from deep sleep mode, congfig the system clock */
  53.     system_clock_recover();
  54.      
  55.     /* wake up from sleep mode */
  56.     printf("\r\nnow exit deepsleep mode by usart1 rdbf interrupt \r\n");
  57.     printf("usart1_rdne_data = 0x%x\r\n", usart1_index);
  58.     delay_ms(300);
  59.   }
  60. }

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

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



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管脚等,这些差异部分请以实际芯片手册为准。
  1. /* enter standby mode */
  2. pwc_standby_mode_enter();
  3. /* enable wakeup pin */
  4. 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函数代码
  1. int main(void)
  2. {
  3. __IO uint32_t index = 0;
  4. /* congfig the system clock */
  5. system_clock_config();
  6. /* init at start board */
  7. at32_board_init();
  8. /* turn on the led light */
  9. at32_led_off(LED2);
  10. at32_led_off(LED3);
  11. at32_led_off(LED4);

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

  14. if(pwc_flag_get(PWC_STANDBY_FLAG) != RESET)
  15. {
  16. /* wakeup from standby */
  17.   pwc_flag_clear(PWC_STANDBY_FLAG);
  18. at32_led_on(LED2);
  19. }

  20. if(pwc_flag_get(PWC_WAKEUP_FLAG) != RESET)
  21. {
  22. /* wakeup event occurs */
  23. pwc_flag_clear(PWC_WAKEUP_FLAG);
  24. at32_led_on(LED3);
  25. }

  26. at32_led_on(LED4);

  27. /*delay to check led status*/
  28. delay_ms(1000);
  29. delay_ms(1000);

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

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

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


6.驱动移植

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

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

  6. /*引脚初始化*/
  7. void OLED_I2C_Init(void)
  8. {
  9.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  10.         
  11.         GPIO_InitTypeDef GPIO_InitStructure;
  12.          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
  13.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  14.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  15.          GPIO_Init(GPIOB, &GPIO_InitStructure);
  16.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  17.          GPIO_Init(GPIOB, &GPIO_InitStructure);
  18.         
  19.         OLED_W_SCL(1);
  20.         OLED_W_SDA(1);
  21. }

  22. /**
  23.   * [url=home.php?mod=space&uid=247401]@brief[/url]  I2C开始
  24.   * @param  无
  25.   * @retval 无
  26.   */
  27. void OLED_I2C_Start(void)
  28. {
  29.         OLED_W_SDA(1);
  30.         OLED_W_SCL(1);
  31.         OLED_W_SDA(0);
  32.         OLED_W_SCL(0);
  33. }

  34. /**
  35.   * [url=home.php?mod=space&uid=247401]@brief[/url]  I2C停止
  36.   * @param  无
  37.   * @retval 无
  38.   */
  39. void OLED_I2C_Stop(void)
  40. {
  41.         OLED_W_SDA(0);
  42.         OLED_W_SCL(1);
  43.         OLED_W_SDA(1);
  44. }

  45. /**
  46.   * @brief  I2C发送一个字节
  47.   * @param  Byte 要发送的一个字节
  48.   * @retval 无
  49.   */
  50. void OLED_I2C_SendByte(uint8_t Byte)
  51. {
  52.         uint8_t i;
  53.         for (i = 0; i < 8; i++)
  54.         {
  55.                 OLED_W_SDA(Byte & (0x80 >> i));
  56.                 OLED_W_SCL(1);
  57.                 OLED_W_SCL(0);
  58.         }
  59.         OLED_W_SCL(1);        //额外的一个时钟,不处理应答信号
  60.         OLED_W_SCL(0);
  61. }

  62. /**
  63.   * @brief  OLED写命令
  64.   * @param  Command 要写入的命令
  65.   * @retval 无
  66.   */
  67. void OLED_WriteCommand(uint8_t Command)
  68. {
  69.         OLED_I2C_Start();
  70.         OLED_I2C_SendByte(0x78);                //从机地址
  71.         OLED_I2C_SendByte(0x00);                //写命令
  72.         OLED_I2C_SendByte(Command);
  73.         OLED_I2C_Stop();
  74. }

  75. /**
  76.   * @brief  OLED写数据
  77.   * @param  Data 要写入的数据
  78.   * @retval 无
  79.   */
  80. void OLED_WriteData(uint8_t Data)
  81. {
  82.         OLED_I2C_Start();
  83.         OLED_I2C_SendByte(0x78);                //从机地址
  84.         OLED_I2C_SendByte(0x40);                //写数据
  85.         OLED_I2C_SendByte(Data);
  86.         OLED_I2C_Stop();
  87. }

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

  100. /**
  101.   * @brief  OLED清屏
  102.   * @param  无
  103.   * @retval 无
  104.   */
  105. void OLED_Clear(void)
  106. {  
  107.         uint8_t i, j;
  108.         for (j = 0; j < 8; j++)
  109.         {
  110.                 OLED_SetCursor(j, 0);
  111.                 for(i = 0; i < 128; i++)
  112.                 {
  113.                         OLED_WriteData(0x00);
  114.                 }
  115.         }
  116. }

  117. /**
  118.   * @brief  OLED显示一个字符
  119.   * @param  Line 行位置,范围:1~4
  120.   * @param  Column 列位置,范围:1~16
  121.   * @param  Char 要显示的一个字符,范围:ASCII可见字符
  122.   * @retval 无
  123.   */
  124. void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
  125. {              
  126.         uint8_t i;
  127.         OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);                //设置光标位置在上半部分
  128.         for (i = 0; i < 8; i++)
  129.         {
  130.                 OLED_WriteData(OLED_F8x16[Char - ' '][i]);                        //显示上半部分内容
  131.         }
  132.         OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);        //设置光标位置在下半部分
  133.         for (i = 0; i < 8; i++)
  134.         {
  135.                 OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);                //显示下半部分内容
  136.         }
  137. }

  138. /**
  139.   * @brief  OLED显示字符串
  140.   * @param  Line 起始行位置,范围:1~4
  141.   * @param  Column 起始列位置,范围:1~16
  142.   * @param  String 要显示的字符串,范围:ASCII可见字符
  143.   * @retval 无
  144.   */
  145. void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
  146. {
  147.         uint8_t i;
  148.         for (i = 0; String[i] != '\0'; i++)
  149.         {
  150.                 OLED_ShowChar(Line, Column + i, String[i]);
  151.         }
  152. }

  153. /**
  154.   * @brief  OLED次方函数
  155.   * @retval 返回值等于X的Y次方
  156.   */
  157. uint32_t OLED_Pow(uint32_t X, uint32_t Y)
  158. {
  159.         uint32_t Result = 1;
  160.         while (Y--)
  161.         {
  162.                 Result *= X;
  163.         }
  164.         return Result;
  165. }

  166. /**
  167.   * @brief  OLED显示数字(十进制,正数)
  168.   * @param  Line 起始行位置,范围:1~4
  169.   * @param  Column 起始列位置,范围:1~16
  170.   * @param  Number 要显示的数字,范围:0~4294967295
  171.   * @param  Length 要显示数字的长度,范围:1~10
  172.   * @retval 无
  173.   */
  174. void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
  175. {
  176.         uint8_t i;
  177.         for (i = 0; i < Length; i++)                                                        
  178.         {
  179.                 OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
  180.         }
  181. }

  182. /**
  183.   * @brief  OLED显示数字(十进制,带符号数)
  184.   * @param  Line 起始行位置,范围:1~4
  185.   * @param  Column 起始列位置,范围:1~16
  186.   * @param  Number 要显示的数字,范围:-2147483648~2147483647
  187.   * @param  Length 要显示数字的长度,范围:1~10
  188.   * @retval 无
  189.   */
  190. void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
  191. {
  192.         uint8_t i;
  193.         uint32_t Number1;
  194.         if (Number >= 0)
  195.         {
  196.                 OLED_ShowChar(Line, Column, '+');
  197.                 Number1 = Number;
  198.         }
  199.         else
  200.         {
  201.                 OLED_ShowChar(Line, Column, '-');
  202.                 Number1 = -Number;
  203.         }
  204.         for (i = 0; i < Length; i++)                                                        
  205.         {
  206.                 OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
  207.         }
  208. }

  209. /**
  210.   * @brief  OLED显示数字(十六进制,正数)
  211.   * @param  Line 起始行位置,范围:1~4
  212.   * @param  Column 起始列位置,范围:1~16
  213.   * @param  Number 要显示的数字,范围:0~0xFFFFFFFF
  214.   * @param  Length 要显示数字的长度,范围:1~8
  215.   * @retval 无
  216.   */
  217. void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
  218. {
  219.         uint8_t i, SingleNumber;
  220.         for (i = 0; i < Length; i++)                                                        
  221.         {
  222.                 SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
  223.                 if (SingleNumber < 10)
  224.                 {
  225.                         OLED_ShowChar(Line, Column + i, SingleNumber + '0');
  226.                 }
  227.                 else
  228.                 {
  229.                         OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
  230.                 }
  231.         }
  232. }

  233. /**
  234.   * @brief  OLED显示数字(二进制,正数)
  235.   * @param  Line 起始行位置,范围:1~4
  236.   * @param  Column 起始列位置,范围:1~16
  237.   * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  238.   * @param  Length 要显示数字的长度,范围:1~16
  239.   * @retval 无
  240.   */
  241. void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
  242. {
  243.         uint8_t i;
  244.         for (i = 0; i < Length; i++)                                                        
  245.         {
  246.                 OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
  247.         }
  248. }

  249. /**
  250.   * @brief  OLED初始化
  251.   * @param  无
  252.   * @retval 无
  253.   */
  254. void OLED_Init(void)
  255. {
  256.         uint32_t i, j;
  257.         
  258.         for (i = 0; i < 1000; i++)                        //上电延时
  259.         {
  260.                 for (j = 0; j < 1000; j++);
  261.         }
  262.         
  263.         OLED_I2C_Init();                        //端口初始化
  264.         
  265.         OLED_WriteCommand(0xAE);        //关闭显示
  266.         
  267.         OLED_WriteCommand(0xD5);        //设置显示时钟分频比/振荡器频率
  268.         OLED_WriteCommand(0x80);
  269.         
  270.         OLED_WriteCommand(0xA8);        //设置多路复用率
  271.         OLED_WriteCommand(0x3F);
  272.         
  273.         OLED_WriteCommand(0xD3);        //设置显示偏移
  274.         OLED_WriteCommand(0x00);
  275.         
  276.         OLED_WriteCommand(0x40);        //设置显示开始行
  277.         
  278.         OLED_WriteCommand(0xA1);        //设置左右方向,0xA1正常 0xA0左右反置
  279.         
  280.         OLED_WriteCommand(0xC8);        //设置上下方向,0xC8正常 0xC0上下反置

  281.         OLED_WriteCommand(0xDA);        //设置COM引脚硬件配置
  282.         OLED_WriteCommand(0x12);
  283.         
  284.         OLED_WriteCommand(0x81);        //设置对比度控制
  285.         OLED_WriteCommand(0xCF);

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

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

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

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

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

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

  3. void OLED_Init(void);
  4. void OLED_Clear(void);
  5. void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
  6. void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
  7. void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
  8. void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
  9. void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
  10. void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);

  11. #endif
oled_font.h文件
  1. #ifndef __OLED_FONT_H
  2. #define __OLED_FONT_H

  3. /*OLED字模库,宽8像素,高16像素*/
  4. const uint8_t OLED_F8x16[][16]=
  5. {
  6.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  7.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//  0
  8.         
  9.         0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,
  10.         0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
  11.         
  12.         0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,
  13.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
  14.         
  15.         0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,
  16.         0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
  17.         
  18.         0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,
  19.         0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
  20.         
  21.         0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,
  22.         0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
  23.         
  24.         0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,
  25.         0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
  26.         
  27.         0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,
  28.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
  29.         
  30.         0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,
  31.         0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
  32.         
  33.         0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,
  34.         0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
  35.         
  36.         0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,
  37.         0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
  38.         
  39.         0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,
  40.         0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
  41.         
  42.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  43.         0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
  44.         
  45.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  46.         0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
  47.         
  48.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  49.         0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
  50.         
  51.         0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,
  52.         0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
  53.         
  54.         0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
  55.         0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
  56.         
  57.         0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,
  58.         0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
  59.         
  60.         0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,
  61.         0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
  62.         
  63.         0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,
  64.         0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
  65.         
  66.         0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,
  67.         0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
  68.         
  69.         0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,
  70.         0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
  71.         
  72.         0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,
  73.         0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
  74.         
  75.         0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,
  76.         0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
  77.         
  78.         0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,
  79.         0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
  80.         
  81.         0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
  82.         0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
  83.         
  84.         0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,
  85.         0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
  86.         
  87.         0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,
  88.         0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
  89.         
  90.         0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,
  91.         0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
  92.         
  93.         0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,
  94.         0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
  95.         
  96.         0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,
  97.         0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
  98.         
  99.         0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,
  100.         0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
  101.         
  102.         0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,
  103.         0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//[url=home.php?mod=space&uid=72445]@[/url] 32
  104.         
  105.         0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,
  106.         0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
  107.         
  108.         0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,
  109.         0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
  110.         
  111.         0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,
  112.         0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
  113.         
  114.         0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,
  115.         0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
  116.         
  117.         0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
  118.         0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
  119.         
  120.         0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,
  121.         0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
  122.         
  123.         0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,
  124.         0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
  125.         
  126.         0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
  127.         0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
  128.         
  129.         0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,
  130.         0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
  131.         
  132.         0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,
  133.         0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
  134.         
  135.         0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,
  136.         0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
  137.         
  138.         0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,
  139.         0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
  140.         
  141.         0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,
  142.         0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
  143.         
  144.         0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,
  145.         0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
  146.         
  147.         0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
  148.         0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
  149.         
  150.         0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,
  151.         0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
  152.         
  153.         0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,
  154.         0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
  155.         
  156.         0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,
  157.         0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
  158.         
  159.         0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,
  160.         0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
  161.         
  162.         0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,
  163.         0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
  164.         
  165.         0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,
  166.         0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
  167.         
  168.         0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,
  169.         0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
  170.         
  171.         0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,
  172.         0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
  173.         
  174.         0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,
  175.         0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
  176.         
  177.         0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,
  178.         0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
  179.         
  180.         0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,
  181.         0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
  182.         
  183.         0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,
  184.         0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
  185.         
  186.         0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,
  187.         0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
  188.         
  189.         0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,
  190.         0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
  191.         
  192.         0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,
  193.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
  194.         
  195.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  196.         0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
  197.         
  198.         0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,
  199.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
  200.         
  201.         0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
  202.         0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
  203.         
  204.         0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,
  205.         0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
  206.         
  207.         0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,
  208.         0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
  209.         
  210.         0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,
  211.         0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
  212.         
  213.         0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
  214.         0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
  215.         
  216.         0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,
  217.         0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
  218.         
  219.         0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
  220.         0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
  221.         
  222.         0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,
  223.         0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
  224.         
  225.         0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,
  226.         0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
  227.         
  228.         0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,
  229.         0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
  230.         
  231.         0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,
  232.         0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
  233.         
  234.         0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,
  235.         0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
  236.         
  237.         0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
  238.         0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
  239.         
  240.         0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,
  241.         0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
  242.         
  243.         0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,
  244.         0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
  245.         
  246.         0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,
  247.         0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
  248.         
  249.         0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,
  250.         0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
  251.         
  252.         0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
  253.         0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
  254.         
  255.         0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,
  256.         0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
  257.         
  258.         0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,
  259.         0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
  260.         
  261.         0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,
  262.         0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
  263.         
  264.         0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
  265.         0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
  266.         
  267.         0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,
  268.         0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
  269.         
  270.         0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,
  271.         0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
  272.         
  273.         0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,
  274.         0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
  275.         
  276.         0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
  277.         0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
  278.         
  279.         0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,
  280.         0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
  281.         
  282.         0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,
  283.         0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
  284.         
  285.         0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,
  286.         0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
  287.         
  288.         0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,
  289.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
  290. };

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


  6. /*引脚初始化*/
  7. void OLED_I2C_Init(void)
  8. {
  9.         
  10.         
  11.         (GPIOB->scr = GPIO_PINS_8);
  12.         (GPIOB->scr = GPIO_PINS_9);
  13. }

  14. /**
  15.   * @brief  I2C开始
  16.   * @param  无
  17.   * @retval 无
  18.   */
  19. void OLED_I2C_Start(void)
  20. {
  21.         (GPIOB->scr = GPIO_PINS_9);
  22.         (GPIOB->scr = GPIO_PINS_8);
  23.         (GPIOB->scr= GPIO_PINS_9);
  24.         (GPIOB->clr= GPIO_PINS_9);
  25. }

  26. /**
  27.   * @brief  I2C停止
  28.   * @param  无
  29.   * @retval 无
  30.   */
  31. void OLED_I2C_Stop(void)
  32. {
  33.         (GPIOB->scr= GPIO_PINS_9);
  34.         (GPIOB->scr = GPIO_PINS_8);
  35.         (GPIOB->scr = GPIO_PINS_9);
  36. }

  37. /**
  38.   * @brief  I2C发送一个字节
  39.   * @param  Byte 要发送的一个字节
  40.   * @retval 无
  41.   */
  42. void OLED_I2C_SendByte(uint8_t Byte)
  43. {
  44.         uint8_t i;
  45.         for (i = 0; i < 8; i++)
  46.         {
  47.                 //OLED_W_SDA(Byte & (0x80 >> i));
  48.                 if(Byte & (0x80 >> i))                GPIOB->scr = GPIO_PINS_9;
  49.                 else                                                                                        GPIOB->clr = GPIO_PINS_9;
  50.                 (GPIOB->scr = GPIO_PINS_8);
  51.                 (GPIOB->clr= GPIO_PINS_9);
  52.         }
  53.         (GPIOB->scr = GPIO_PINS_8);        //额外的一个时钟,不处理应答信号
  54.         (GPIOB->clr= GPIO_PINS_9);
  55. }

  56. /**
  57.   * @brief  OLED写命令
  58.   * @param  Command 要写入的命令
  59.   * @retval 无
  60.   */
  61. void OLED_WriteCommand(uint8_t Command)
  62. {
  63.         OLED_I2C_Start();
  64.         OLED_I2C_SendByte(0x78);                //从机地址
  65.         OLED_I2C_SendByte(0x00);                //写命令
  66.         OLED_I2C_SendByte(Command);
  67.         OLED_I2C_Stop();
  68. }

  69. /**
  70.   * @brief  OLED写数据
  71.   * @param  Data 要写入的数据
  72.   * @retval 无
  73.   */
  74. void OLED_WriteData(uint8_t Data)
  75. {
  76.         OLED_I2C_Start();
  77.         OLED_I2C_SendByte(0x78);                //从机地址
  78.         OLED_I2C_SendByte(0x40);                //写数据
  79.         OLED_I2C_SendByte(Data);
  80.         OLED_I2C_Stop();
  81. }

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

  94. /**
  95.   * @brief  OLED清屏
  96.   * @param  无
  97.   * @retval 无
  98.   */
  99. void OLED_Clear(void)
  100. {  
  101.         uint8_t i, j;
  102.         for (j = 0; j < 8; j++)
  103.         {
  104.                 OLED_SetCursor(j, 0);
  105.                 for(i = 0; i < 128; i++)
  106.                 {
  107.                         OLED_WriteData(0x00);
  108.                 }
  109.         }
  110. }

  111. /**
  112.   * @brief  OLED显示一个字符
  113.   * @param  Line 行位置,范围:1~4
  114.   * @param  Column 列位置,范围:1~16
  115.   * @param  Char 要显示的一个字符,范围:ASCII可见字符
  116.   * @retval 无
  117.   */
  118. void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
  119. {              
  120.         uint8_t i;
  121.         OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);                //设置光标位置在上半部分
  122.         for (i = 0; i < 8; i++)
  123.         {
  124.                 OLED_WriteData(OLED_F8x16[Char - ' '][i]);                        //显示上半部分内容
  125.         }
  126.         OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);        //设置光标位置在下半部分
  127.         for (i = 0; i < 8; i++)
  128.         {
  129.                 OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);                //显示下半部分内容
  130.         }
  131. }

  132. /**
  133.   * @brief  OLED显示字符串
  134.   * @param  Line 起始行位置,范围:1~4
  135.   * @param  Column 起始列位置,范围:1~16
  136.   * @param  String 要显示的字符串,范围:ASCII可见字符
  137.   * @retval 无
  138.   */
  139. void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
  140. {
  141.         uint8_t i;
  142.         for (i = 0; String[i] != '\0'; i++)
  143.         {
  144.                 OLED_ShowChar(Line, Column + i, String[i]);
  145.         }
  146. }

  147. /**
  148.   * @brief  OLED次方函数
  149.   * @retval 返回值等于X的Y次方
  150.   */
  151. uint32_t OLED_Pow(uint32_t X, uint32_t Y)
  152. {
  153.         uint32_t Result = 1;
  154.         while (Y--)
  155.         {
  156.                 Result *= X;
  157.         }
  158.         return Result;
  159. }

  160. /**
  161.   * @brief  OLED显示数字(十进制,正数)
  162.   * @param  Line 起始行位置,范围:1~4
  163.   * @param  Column 起始列位置,范围:1~16
  164.   * @param  Number 要显示的数字,范围:0~4294967295
  165.   * @param  Length 要显示数字的长度,范围:1~10
  166.   * @retval 无
  167.   */
  168. void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
  169. {
  170.         uint8_t i;
  171.         for (i = 0; i < Length; i++)                                                        
  172.         {
  173.                 OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
  174.         }
  175. }

  176. /**
  177.   * @brief  OLED显示数字(十进制,带符号数)
  178.   * @param  Line 起始行位置,范围:1~4
  179.   * @param  Column 起始列位置,范围:1~16
  180.   * @param  Number 要显示的数字,范围:-2147483648~2147483647
  181.   * @param  Length 要显示数字的长度,范围:1~10
  182.   * @retval 无
  183.   */
  184. void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
  185. {
  186.         uint8_t i;
  187.         uint32_t Number1;
  188.         if (Number >= 0)
  189.         {
  190.                 OLED_ShowChar(Line, Column, '+');
  191.                 Number1 = Number;
  192.         }
  193.         else
  194.         {
  195.                 OLED_ShowChar(Line, Column, '-');
  196.                 Number1 = -Number;
  197.         }
  198.         for (i = 0; i < Length; i++)                                                        
  199.         {
  200.                 OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
  201.         }
  202. }

  203. /**
  204.   * @brief  OLED显示数字(十六进制,正数)
  205.   * @param  Line 起始行位置,范围:1~4
  206.   * @param  Column 起始列位置,范围:1~16
  207.   * @param  Number 要显示的数字,范围:0~0xFFFFFFFF
  208.   * @param  Length 要显示数字的长度,范围:1~8
  209.   * @retval 无
  210.   */
  211. void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
  212. {
  213.         uint8_t i, SingleNumber;
  214.         for (i = 0; i < Length; i++)                                                        
  215.         {
  216.                 SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
  217.                 if (SingleNumber < 10)
  218.                 {
  219.                         OLED_ShowChar(Line, Column + i, SingleNumber + '0');
  220.                 }
  221.                 else
  222.                 {
  223.                         OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
  224.                 }
  225.         }
  226. }

  227. /**
  228.   * @brief  OLED显示数字(二进制,正数)
  229.   * @param  Line 起始行位置,范围:1~4
  230.   * @param  Column 起始列位置,范围:1~16
  231.   * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  232.   * @param  Length 要显示数字的长度,范围:1~16
  233.   * @retval 无
  234.   */
  235. void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
  236. {
  237.         uint8_t i;
  238.         for (i = 0; i < Length; i++)                                                        
  239.         {
  240.                 OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
  241.         }
  242. }

  243. /**
  244.   * @brief  OLED初始化
  245.   * @param  无
  246.   * @retval 无
  247.   */
  248. void OLED_Init(void)
  249. {
  250.         uint32_t i, j;
  251.         
  252.         for (i = 0; i < 1000; i++)                        //上电延时
  253.         {
  254.                 for (j = 0; j < 1000; j++);
  255.         }
  256.         
  257.         OLED_I2C_Init();                        //端口初始化
  258.         
  259.         OLED_WriteCommand(0xAE);        //关闭显示
  260.         
  261.         OLED_WriteCommand(0xD5);        //设置显示时钟分频比/振荡器频率
  262.         OLED_WriteCommand(0x80);
  263.         
  264.         OLED_WriteCommand(0xA8);        //设置多路复用率
  265.         OLED_WriteCommand(0x3F);
  266.         
  267.         OLED_WriteCommand(0xD3);        //设置显示偏移
  268.         OLED_WriteCommand(0x00);
  269.         
  270.         OLED_WriteCommand(0x40);        //设置显示开始行
  271.         
  272.         OLED_WriteCommand(0xA1);        //设置左右方向,0xA1正常 0xA0左右反置
  273.         
  274.         OLED_WriteCommand(0xC8);        //设置上下方向,0xC8正常 0xC0上下反置

  275.         OLED_WriteCommand(0xDA);        //设置COM引脚硬件配置
  276.         OLED_WriteCommand(0x12);
  277.         
  278.         OLED_WriteCommand(0x81);        //设置对比度控制
  279.         OLED_WriteCommand(0xCF);

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

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

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

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

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

  288.         OLED_WriteCommand(0xAF);        //开启显示
  289.                
  290.         OLED_Clear();                                //OLED清屏
  291. }
下图是移植后的OLED显示结果,只用在main.c中调用驱动即可。
main.c文件
  1. /**
  2.   **************************************************************************
  3.   * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  4.   * @brief    main program
  5.   **************************************************************************
  6.   *                       Copyright notice & Disclaimer
  7.   *
  8.   * The software Board Support Package (BSP) that is made available to
  9.   * download from Artery official website is the copyrighted work of Artery.
  10.   * Artery authorizes customers to use, copy, and distribute the BSP
  11.   * software and its related documentation for the purpose of design and
  12.   * development in conjunction with Artery microcontrollers. Use of the
  13.   * software is governed by this copyright notice and the following disclaimer.
  14.   *
  15.   * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
  16.   * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
  17.   * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
  18.   * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
  19.   * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  20.   * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
  21.   *
  22.   **************************************************************************
  23.   */

  24. #include "at32l021_board.h"
  25. #include "at32l021_clock.h"
  26. #include "i2c_application.h"
  27. #include "OLED.h"


  28. /** @addtogroup AT32L021_periph_examples
  29.   * @{
  30.   */

  31. void gpio_config(void)
  32. {
  33.   gpio_init_type gpio_init_struct;

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

  36.   /* set default parameter */
  37.   gpio_default_para_init(&gpio_init_struct);

  38.   /* configure the gpio */
  39.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  40.   gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_OPEN_DRAIN;
  41.   gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  42.   gpio_init_struct.gpio_pins = GPIO_PINS_8;
  43.   gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  44.   gpio_init(GPIOB, &gpio_init_struct);
  45.         
  46.           /* configure the gpio */
  47.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  48.   gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_OPEN_DRAIN;
  49.   gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  50.   gpio_init_struct.gpio_pins = GPIO_PINS_9;
  51.   gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  52.   gpio_init(GPIOB, &gpio_init_struct);
  53.         
  54.                   /* configure the gpio */
  55.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  56.   gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  57.   gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  58.   gpio_init_struct.gpio_pins = GPIO_PINS_11;
  59.   gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  60.   gpio_init(GPIOB, &gpio_init_struct);
  61. }





  62. i2c_handle_type hi2cx;

  63. /**
  64.   * @brief  error handler program
  65.   * @param  i2c_status
  66.   * @retval none
  67.   */
  68. void error_handler(uint32_t error_code)
  69. {
  70.   while(1)
  71.   {

  72.   }
  73. }


  74. /**
  75.   * @brief  main function.
  76.   * @param  none
  77.   * @retval none
  78.   */
  79. int main(void)
  80. {

  81.   /* initial system clock */
  82.   system_clock_config();

  83.   /* at board initial */
  84.   at32_board_init();

  85.         gpio_config();
  86.         
  87.   while(1)
  88.   {
  89.                         OLED_Init();
  90.         
  91.                         OLED_ShowChar(1, 1, 'A');
  92.                         OLED_ShowString(1, 3, "HelloWorld!");
  93.                         OLED_ShowNum(2, 1, 12345, 5);
  94.                         OLED_ShowSignedNum(2, 7, -66, 2);
  95.                         OLED_ShowHexNum(3, 1, 0xAA55, 4);
  96.                         OLED_ShowBinNum(4, 1, 0xAA55, 16);

  97.                 GPIOB->scr = GPIO_PINS_11;
  98.     delay_ms(500);
  99.                 GPIOB->clr = GPIO_PINS_11;



  100.   }
  101. }


  102. /**
  103.   * @}
  104.   */

  105. /**
  106.   * @}
  107.   */
258646751965ad3748.jpg

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

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


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

打赏榜单

ArteryMCU 打赏了 30.00 元 2025-01-09
理由:[L021开发板评测活动]内容优质

您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

144

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部