SDK 应用开发说明

本文档主要是协助用户快速熟悉杰理 AC79 的 SDK 流程和框架,来完成 AC79_DevKitBoard 的相关软件开发工作。

参考文档: https://doc.zh-jieli.com/AC79/zh-cn/master/getting_started/sdk_app_development/index.html

0.基础功能开发 - 图1

下面是杰理开发的三条重要信息:

  1. 杰理开发重点关注:board.c 和 app_config.h
  2. 杰理开发重点关注:board.c 和 app_config.h
  3. 杰理开发重点关注:board.c 和 app_config.h

borad.c里面定义了开发板相关的外设io口配置, app_config.h中声明了相关的功能开关

  1. 在board.c文件中, 将串口波特率改为115200
  2. 在app_config.h文件中定义CONFIG_DEBUG_ENABLE,打开串口调试
    1. #if CONFIG_DEBUG_ENABLE
    2. UART1_PLATFORM_DATA_BEGIN(uart1_data)//打印串口
    3. .baudrate = 115200,//
    4. .port = PORT_REMAP,//任意IO通道
    5. #if CONFIG_AUDIO_ENC_SAMPLE_SOURCE == AUDIO_ENC_SAMPLE_SOURCE_PLNK0
    6. .output_channel = OUTPUT_CHANNEL3,//选择映射输出通道
    7. #else
    8. .output_channel = OUTPUT_CHANNEL0,
    9. #endif
    10. .tx_pin = IO_PORTB_03,
    11. .rx_pin = -1,
    12. .max_continue_recv_cnt = 1024,
    13. .idle_sys_clk_cnt = 500000,
    14. .clk_src = PLL_48M,
    15. .flags = UART_DEBUG,
    16. UART1_PLATFORM_DATA_END();
    17. #endif

    按键

    按键的配置

    这个案例中,我们以adc按键为例,我们首先打开DevKitBoard.c文件,找到与按键相关的配置
    1. #if TCFG_ADKEY_ENABLE
    2. #define ADKEY_UPLOAD_R 22
    3. #define ADC_VDDIO (0x3FF)
    4. #define ADC_09 (0x3FF)
    5. #define ADC_08 (0x3FF)
    6. #define ADC_07 (0x3FF * 150 / (150 + ADKEY_UPLOAD_R))
    7. #define ADC_06 (0x3FF * 62 / (62 + ADKEY_UPLOAD_R))
    8. #define ADC_05 (0x3FF * 36 / (36 + ADKEY_UPLOAD_R))
    9. #define ADC_04 (0x3FF * 22 / (22 + ADKEY_UPLOAD_R))
    10. #define ADC_03 (0x3FF * 13 / (13 + ADKEY_UPLOAD_R))
    11. //#define ADC_02 (0x3FF * 75 / (75 + ADKEY_UPLOAD_R * 10))
    12. //#define ADC_01 (0x3FF * 3 / (3 + ADKEY_UPLOAD_R))
    13. #define ADC_00 (0)
    14. #define ADKEY_V_9 ((ADC_09 + ADC_VDDIO)/2)
    15. #define ADKEY_V_8 ((ADC_08 + ADC_09)/2)
    16. #define ADKEY_V_7 ((ADC_07 + ADC_08)/2 + 50)
    17. #define ADKEY_V_6 ((ADC_06 + ADC_07)/2)
    18. #define ADKEY_V_5 ((ADC_05 + ADC_06)/2)
    19. #define ADKEY_V_4 ((ADC_04 + ADC_05)/2)
    20. #define ADKEY_V_3 ((ADC_03 + ADC_04)/2)
    21. //#define ADKEY_V_2 ((ADC_02 + ADC_03)/2)
    22. //#define ADKEY_V_1 ((ADC_01 + ADC_02)/2)
    23. //#define ADKEY_V_0 ((ADC_00 + ADC_01)/2)
    24. const struct adkey_platform_data adkey_data = {
    25. .enable = 1,
    26. .adkey_pin = IO_PORTB_01,
    27. .extern_up_en = 1,
    28. .ad_channel = 3,
    29. .ad_value = {
    30. //ADKEY_V_0,//122 //0~122
    31. //ADKEY_V_1,//192 //122~192
    32. //ADKEY_V_2,//319 //192~319
    33. ADKEY_V_3,//445 //319~445
    34. ADKEY_V_4,//572 //445~572
    35. ADKEY_V_5,//694 //572~694
    36. ADKEY_V_6,//823 //694~823
    37. ADKEY_V_7,//1007 //823~1007
    38. ADKEY_V_8,//1023 //1007~1023
    39. ADKEY_V_9,//1023 //1023
    40. },
    41. .key_value = {
    42. KEY_5,
    43. KEY_4,
    44. KEY_3,
    45. KEY_2,
    46. KEY_1,
    47. NO_KEY,
    48. NO_KEY,
    49. },
    50. };
    51. #endif
    当我们看到这种带有#if 条件 的宏定义的时候, 首先想想这个宏定义有没有配置在哪里配置,当然是在前面讲过的app_config.h文件里面配置了啊,重要的事情已经说过三遍啦!

打开app_config.h文件,先搜索TCFG_ADKEY_ENABLE有没有配置,若没有配置,则配置

  1. #define TCFG_ADKEY_ENABLE 1 //AD按键

按键的回调

我们可以在app_main.c文件中的事件回调函数中,增加按键相关的回调函数,下面的打印的value就是我们在board.c文件里面配置的value值

  1. static int app_demo_event_handler(struct application *app, struct sys_event *sys_event)
  2. {
  3. switch (sys_event->type) {
  4. case SYS_NET_EVENT:
  5. break;
  6. case SYS_KEY_EVENT:
  7. struct key_event* key = (struct key_event *)sys_event->payload;
  8. printf("key=%d value=%d \n",key->action,key->value);
  9. break;
  10. default:
  11. return false;
  12. }
  13. }

参考文档:https://doc.zh-jieli.com/AC79/zh-cn/master/module_example/peripherals/key.html

GPIO

gpio开发相对来说要简单很多,我们以点亮开发板上面的led灯为例,
image.png

代码实现

  1. #include "app_config.h"
  2. #include "system/includes.h"
  3. #include "asm/pwm.h"
  4. #include "device/device.h"
  5. #define ITHEIMA_LED_PIN IO_PORTC_00
  6. void itheima_led_init(){
  7. }
  8. void itheima_led_set_status(uint8_t state){
  9. gpio_direction_output(ITHEIMA_LED_PIN, state);
  10. }
  11. void itheima_test_led_task(){
  12. int i = 0;
  13. while(1){
  14. itheima_led_set_status(i);
  15. i = !i;
  16. os_time_dly(100);
  17. }
  18. }
  19. void itheima_test_led_main(){
  20. os_task_create(itheima_test_led_task,NULL,10,512,0,"itheima_test_led_task");
  21. }
  22. late_initcall(itheima_test_led_main);

参考文档:https://doc.zh-jieli.com/AC79/zh-cn/master/module_example/peripherals/gpio.html

PWM

image.png

配置

image.png

在board.c文件中配置

  1. PWM_PLATFORM_DATA_BEGIN(pwm_data2)
  2. .port = IO_PORTC_02,//选择定时器的TIMER PWM任意IO,pwm_ch加上PWM_TIMER3_OPCH3或PWM_TIMER2_OPCH2有效,只支持2个PWM,占用output_channel2/3,其他外设使用output_channel需留意
  3. .pwm_ch = PWMCH4_H,//初始化可选多通道,如:PWMCH0_H | PWMCH0_L | PWMCH1_H ... | PWMCH7_H | PWMCH7_L | PWM_TIMER2_OPCH2 | PWM_TIMER3_OPCH3 ,
  4. .freq = 1000,//频率
  5. .duty = 50,//占空比
  6. .point_bit = 0,//根据point_bit值调节占空比小数点精度位: 0<freq<=4K,point_bit=2;4K<freq<=40K,point_bit=1; freq>40K,point_bit=0;
  7. PWM_PLATFORM_DATA_END()

配置完成之后,还要记得注册设备

  1. REGISTER_DEVICES(device_table) = { //注册模块 系统使用模块时会根据配置进行初始化
  2. #ifdef CONFIG_PWM_ENABLE
  3. { "pwm1", &pwm_dev_ops, (void *)&pwm_data1},
  4. { "pwm2", &pwm_dev_ops, (void *)&pwm_data2},
  5. /* { "pwm_led",&pwm_led_ops, (void *)&pwm_led_data}, */
  6. #endif

示例代码:

  1. void itheima_led_test_pwm_task(){
  2. // 1. 打开pwm设备
  3. void *pwm_dev_handl = NULL;
  4. struct pwm_platform_data pwm = {0};
  5. /*1.open */
  6. pwm_dev_handl = dev_open("pwm2", &pwm);//打开PWM0设备,传参可以获取board.c配置的参数
  7. if (!pwm_dev_handl) {
  8. printf("open pwm err !!!\n\n");
  9. return ;
  10. }
  11. printf("pwm : ch=0x%x,duty=%2f%%,pbit=%d,freq=%dHz\n", pwm.pwm_ch, pwm.duty, pwm.point_bit, pwm.freq);
  12. // 2. 运行pwm
  13. dev_ioctl(pwm_dev_handl, PWM_RUN, (u32)&pwm);
  14. int i = 100;
  15. while (1) {
  16. // 3. 改变pwm占空比
  17. pwm.duty = i;
  18. dev_ioctl(pwm_dev_handl, PWM_SET_DUTY, (u32)&pwm);//设置占空比
  19. os_time_dly(5);
  20. i--;
  21. // 条件判断
  22. if(i < 0){
  23. i = 100;
  24. }
  25. }
  26. }
  27. void itheima_test_led_main(){
  28. os_task_create(itheima_led_test_pwm_task,NULL,10,512,0,"itheima_led_test_pwm_task");
  29. }
  30. late_initcall(itheima_test_led_main);

参考文档: https://doc.zh-jieli.com/AC79/zh-cn/master/module_example/peripherals/pwm.html

串口收发

首先需要对串口进行相应的配置,让它能够支持收发数据, 在board.c文件中进行如下配置

  1. #if CONFIG_DEBUG_ENABLE
  2. UART1_PLATFORM_DATA_BEGIN(uart1_data)//打印串口
  3. .baudrate = 115200,//
  4. .port = PORT_REMAP,//任意IO通道
  5. #if CONFIG_AUDIO_ENC_SAMPLE_SOURCE == AUDIO_ENC_SAMPLE_SOURCE_PLNK0
  6. .output_channel = OUTPUT_CHANNEL3,//选择映射输出通道
  7. #else
  8. .output_channel = OUTPUT_CHANNEL0,
  9. #endif
  10. .input_channel = INPUT_CHANNEL3,
  11. .tx_pin = IO_PORTB_03,
  12. .rx_pin = IO_PORTB_04,
  13. .max_continue_recv_cnt = 1024,
  14. .idle_sys_clk_cnt = 500000,
  15. .clk_src = PLL_48M,
  16. .flags = UART_DEBUG,
  17. UART1_PLATFORM_DATA_END();
  18. #endif

配置完成之后,记得检查设备有没有被注册
image.png

串口初始化

  1. void icheima_uart_init(char* name){
  2. hdl = dev_open(name, NULL);
  3. if (!hdl) {
  4. printf("open uart err:%s !!!\n",name);
  5. return ;
  6. }
  7. /* 1 . 设置接收数据地址 */
  8. dev_ioctl(hdl, UART_SET_CIRCULAR_BUFF_ADDR, (int)uart_buf);
  9. /* 2 . 设置接收数据地址长度 */
  10. dev_ioctl(hdl, UART_SET_CIRCULAR_BUFF_LENTH, sizeof(uart_buf));
  11. /* 3 . 设置接收数据为阻塞方式,需要非阻塞可以去掉,建议加上超时设置 */
  12. dev_ioctl(hdl, UART_SET_RECV_BLOCK, 1);
  13. //u32 parm = 500;//接收函数的超时时间要比发送函数超时时间小
  14. //dev_ioctl(hdl, UART_SET_RECV_TIMEOUT, (u32)parm);
  15. /* 4 . 使能特殊串口 */
  16. dev_ioctl(hdl, UART_START, 0);
  17. printf("---> icheima_uart_init uart_recv_test_task running \n");
  18. }

收数据

  1. /**
  2. 接收数据
  3. */
  4. int icheima_uart_read_data(uint8_t* buf){
  5. int len = dev_read(hdl, buf, 64);
  6. if (len <= 0) {
  7. printf("\n uart recv err len = %d\n", len);
  8. if (len == UART_CIRCULAR_BUFFER_WRITE_OVERLAY) {
  9. printf("\n UART_CIRCULAR_BUFFER_WRITE_OVERLAY err\n");
  10. dev_ioctl(hdl, UART_FLUSH, 0); //如果由于用户长期不取走接收的数据导致循环buf接收回卷覆盖,因此直接冲掉循环buf所有数据重新接收
  11. } else if (len == UART_RECV_TIMEOUT) {
  12. puts("UART_RECV_TIMEOUT...\r\n");
  13. }
  14. }
  15. return len;
  16. }
  17. #ifdef USE_ICHEIMA_UART_DEMO_TEST
  18. #include "json.h"
  19. // 串口接收到消息之后,就将消息发给gd32
  20. static void uart_recv_test_task(void *priv){
  21. int len=0;
  22. uint8_t recv_buf[1024];
  23. printf("uart_recv_test_task start>>>>>>>>>>>>>>>>>\r\n");
  24. json_object *new_obj;
  25. const char *json_str, *str_ssid, *uuid;
  26. while(1){
  27. len=icheima_uart_read_data(recv_buf);
  28. printf("\n uart recv len = %d\n", len);
  29. if(len > 0){
  30. printf("\n uart recv len = %d\n", len);
  31. //recv_buf[len] = '\0';
  32. memset(recv_buf, 0, sizeof(recv_buf));
  33. }else{
  34. printf("uart recv error len = %d\n", len);
  35. }
  36. }
  37. }

启动收消息的线程

  1. os_task_create(uart_recv_test_task, NULL, 10, 1000, 0, "uart_recv_test_task");

发数据

  1. /**
  2. 向外面发送数据
  3. */
  4. void icheima_uart_send_data(uint8_t* data, uint32_t len){
  5. dev_write(hdl, data, len);
  6. }

一些配置说明

修改蓝牙名称

apps/common/config/user_cfg.c文件中找到下面这个函数,将它修改为自己想要的名称
注意: 以”JL-“开头, 方便继续后续的学习

  1. const char *bt_get_local_name(void)
  2. {
  3. #ifndef CONFIG_RF_TEST_ENABLE
  4. const u8 *mac_addr;
  5. mac_addr = bt_get_mac_addr();
  6. sprintf(edr_name, "JL-ICHEIMA-%02X%02X", mac_addr[4], mac_addr[5]);
  7. #endif
  8. return edr_name;
  9. }

参考文档: https://doc.zh-jieli.com/Tools/zh-cn/dev_tools/dev_env/index.html