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

[活动专区] 【AT-START-WB415测评】综合测试

[复制链接]
 楼主| qintian0303 发表于 2022-9-14 15:15 | 显示全部楼层 |阅读模式
<
本帖最后由 qintian0303 于 2022-9-14 15:15 编辑

概述
  非常感谢21ic论坛和雅特力组织这次活动,让我们又一次认识了以为新朋友,很快就收到了开发板,不过只有一个裸板,还因为运输问题出现了部分引脚的的损坏,不过不影响本次测试,大力的将它复原就可以了。
  开发板收到后就对上电欣赏了一下内置的程序,简单的LED操作,这些不重要,重要的还是要先了解一下开发板的资源,开展系列测试计划。

资源分析
  开发板板载AT-Link下载工具;
  使用的是AT32F403CCT6作为Link的主控芯片,M4核,最高150 MHz工作频率,不过只能分频到144;
  芯片默认是FLASH启动;
  射频天线器件包含一个板载PCB天线和进行专业性能测试的SMA接口;
  板载的LED分别是红、黄、绿各一个,供电指示灯个人建议用绿色的更好;
  用户按键使用了不同颜色的按键作为区分,不过真正可以进行功能按键的只有一个;
  SPI,IIC,串口等接口都有,种类齐全不过接口数量少;

需求分析
  由以上资源的所支撑的,我们初步对测试内容和资源进行分析和分配,基本原则如下:
  SPI接口的常用器件有存储器(例如W25Q系列),支持SPI的TFT等,本次测试使用支持SPI通信的TFT,有利于整个测试过程的状态展示;
  IIC接口一般是各种传感器使用,本次选用AHT20温湿度传感器进行展示;
  串口可以通过PC测试,同时该开发板所使用的的芯片中的内置蓝牙同样是使用串口通信;
  确定这些基本测试后并结合板载的LED和按键,基本就能满足本次测试需要。
  初步的需求分析思维导图:
屏幕截图.jpg

具体实现
  根据思维导图我们对于具体的需求进行实际的分析。
  首先作为这里的唯一输入对象,按键的识别其实是最主要的,其次是显示功能,然后根据各个界面去实现对应的功能,当然在这些操作之前,给单片机上一下发条还是非常必须的(时钟配置);
1)时钟配置
  时钟配置离不开芯片的时钟树,可以清晰直观的进行各部时钟配置的选择
0CA3B2881B5546E398403A0B01797C5E.jpg

  其实在头文件中就有头文件中 EXTERN  SystemInit就是执行的的时钟配置,在system_at32wb415.c的SystemInit如下:
0CA3B2881B5546E398403A0B01797C5E.jpg

  由上图可以看到是直接进行的寄存器赋值,这样其实是不适合我们直接修改操作的,不易理解还容易出错,所以在这之外雅特力在main中又进行了一遍时钟配置system_clock_config();可以通过修改里面的寄存器配置。AT32WB415CCU7-7目前不考虑功耗,由于USB的存在必须能够通过PLLCLK分频得到48M,所以PLLCLK在150M的限值下最大可以设计成144,HEXT通过18倍频后得到PLLCLK。
2)按键配置
  按键作为目前开发板的唯一输入,准确快速获取其状态是非常有必要的,本次采用外部中断+定时器的方式来进行按键状态的判断,注意所有引脚都可以被配置为外部中断。
  定时器配置:基本定时器是用定时器10,注意分频的计算,Period对应定时ms;
  1. void Tmr10Base_init(uint16_t Period)
  2. {
  3.   /* enable tmr10 clock */
  4.   crm_periph_clock_enable(CRM_TMR10_PERIPH_CLOCK, TRUE);
  5.   
  6.   /* tmr1 configuration */
  7.   /* time base configuration */
  8.   /* systemclock/14400/10000 = 1hz */
  9.   tmr_base_init(TMR10, Period * 10 - 1, 14400 - 1);
  10.   tmr_cnt_dir_set(TMR10, TMR_COUNT_UP);
  11.   
  12.   /* overflow interrupt enable */
  13.   tmr_interrupt_enable(TMR10, TMR_OVF_INT, TRUE);

  14.   /* tmr10 overflow interrupt nvic init */
  15.   nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  16.   nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 0, 2);

  17.   /* enable tmr10 */
  18.   tmr_counter_enable(TMR10, TRUE);
  19. }
  外部中断配置:按键对应的IO为PA0
  1. void port_EXIT_init(void)
  2. {
  3.   exint_init_type exint_init_struct;

  4.   crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
  5.   crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

  6.   gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE0);

  7.   exint_default_para_init(&exint_init_struct);
  8.   exint_init_struct.line_enable = TRUE;
  9.   exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
  10.   exint_init_struct.line_select = EXINT_LINE_0;
  11.   exint_init_struct.line_polarity = EXINT_TRIGGER_RISING_EDGE;
  12.   exint_init(&exint_init_struct);

  13.   nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  14.   nvic_irq_enable(EXINT0_IRQn, 1, 0);
  15. }
  到这里只是一个基本功能的配置,为了实现不阻塞,所有的操作都是对标志位的修改,为此建立一个结构体;
  1. typedef struct
  2. {
  3. uint8_t EXIT_flag; //中断触发标志
  4. uint8_t EXIT_Data; //中断触发防抖计时
  5. uint8_t Press_flag; //按键触发标志
  6. uint8_t Press_Data; //按键类型判断计时
  7. uint8_t ShortPress_flag; //短按触发标志
  8. uint8_t LongPress_flag; //长按触发标志
  9. }key;
  10. key key_Ok;
  在外部中断中只进行EXIT_flag的复位,最主要是通过定时器中进行防抖和按键识别:
  1. if(key_Ok.EXIT_flag == 1)//防抖判断
3)tft驱动
  首先了解一下本次使用的tft,1.54吋,IPS高清显示,分辨率240*240,驱动芯片为ST7789,支持MCU和SPI两种通信方式,本次通过SPI方式驱动液晶屏,相对来说分辨率不低,液晶屏SPI通信时只能作为从机接收数据,所以只用到了MOSI和SCK,CS和RS通过软件控制,复位和背光控制通过软件控制。
  初始化代码:
  1. #define CS_OUT0       gpio_bits_reset(GPIOA,GPIO_PINS_4)
  2. #define CS_OUT1       gpio_bits_set(GPIOA,GPIO_PINS_4)

  3. #define TFT_RS_reset            gpio_bits_reset(GPIOA,GPIO_PINS_5)
  4. #define TFT_RS_set              gpio_bits_set(GPIOA,GPIO_PINS_5)
  5. #define TFT_RESET_reset         gpio_bits_reset(GPIOA,GPIO_PINS_3)
  6. #define TFT_RESET_set           gpio_bits_set(GPIOA,GPIO_PINS_3)
  7. #define TFT_BL_SET              gpio_bits_set(GPIOA,GPIO_PINS_2)
  8. #define TFT_BL_RESET            gpio_bits_reset(GPIOA,GPIO_PINS_2)
  9. void SPI_IOInit(void)
  10. {
  11.   gpio_init_type gpio_initstructure;
  12.   spi_init_type spi_init_struct;

  13.   crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  14.   crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
  15.   
  16.   /* software cs, pa4 as a general io to control flash cs */
  17.   gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  18.   gpio_initstructure.gpio_pull           = GPIO_PULL_UP;
  19.   gpio_initstructure.gpio_mode           = GPIO_MODE_OUTPUT;
  20.   gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  21.   gpio_initstructure.gpio_pins           = GPIO_PINS_4|GPIO_PINS_5|GPIO_PINS_3;
  22.   gpio_init(GPIOA, &gpio_initstructure);
  23.   
  24.   gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  25.   gpio_initstructure.gpio_mode           = GPIO_MODE_OUTPUT;
  26.   gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  27.   gpio_initstructure.gpio_pull           = GPIO_PULL_DOWN;
  28.   gpio_initstructure.gpio_pins           = GPIO_PINS_2;
  29.   gpio_init(GPIOA, &gpio_initstructure);
  30.   
  31.   CS_OUT0;
  32.   TFT_RS_reset;
  33.   TFT_RESET_reset;
  34.   TFT_BL_RESET;
  35.   /* sck */
  36.   gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  37.   gpio_initstructure.gpio_pull           = GPIO_PULL_UP;
  38.   gpio_initstructure.gpio_mode           = GPIO_MODE_MUX;
  39.   gpio_initstructure.gpio_pins           = GPIO_PINS_13;
  40.   gpio_init(GPIOB, &gpio_initstructure);
  41.   /* mosi */
  42.   gpio_initstructure.gpio_pull           = GPIO_PULL_DOWN;
  43.   gpio_initstructure.gpio_mode           = GPIO_MODE_MUX;
  44.   gpio_initstructure.gpio_pins           = GPIO_PINS_15;
  45.   gpio_init(GPIOB, &gpio_initstructure);

  46.   crm_periph_clock_enable(CRM_SPI2_PERIPH_CLOCK, TRUE);
  47.   spi_default_para_init(&spi_init_struct);
  48.   spi_init_struct.transmission_mode     = SPI_TRANSMIT_FULL_DUPLEX;
  49.   spi_init_struct.master_slave_mode     = SPI_MODE_MASTER;
  50.   spi_init_struct.mclk_freq_division    = SPI_MCLK_DIV_8;
  51.   spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;
  52.   spi_init_struct.frame_bit_num         = SPI_FRAME_8BIT;
  53.   spi_init_struct.clock_polarity        = SPI_CLOCK_POLARITY_HIGH;
  54.   spi_init_struct.clock_phase           = SPI_CLOCK_PHASE_2EDGE;
  55.   spi_init_struct.cs_mode_selection     = SPI_CS_SOFTWARE_MODE;
  56.   spi_init(SPI2, &spi_init_struct);
  57.   spi_enable(SPI2, TRUE);
  58. }

  59. void SPI_Send_Data(uint8_t Data)
  60. {
  61.   
  62.   CS_OUT0;                                                              //选中该从机
  63.   delay_us(1);
  64.   
  65.   spi_i2s_data_transmit(SPI2, Data);
  66.   while(spi_i2s_flag_get(SPI2, SPI_I2S_TDBE_FLAG) == RESET);
  67.   
  68.   delay_us(1);
  69.   CS_OUT1;                                                            

  70. }
  注意CS_OUT1;的前面加的delay_us(1);是不可少的,可能上升太快导致通信异常。
4)界面设计
  界面的控制通过按键的短按和长按进行来实现的,例如界面菜单的切换通过短按实现,具体进入和退出界面通过长按来实现,这时候就需要对按键状态进行判断处理和执行界面切换和刷新操作;
  界面的分配:
  1. #define           Holle_Interface               1                               //开机欢迎界面
  2. #define           Menu_Interface                2                               //菜单界面
  3. #define           LEDTest_Interface             3                               //LED测试界面
  4. #define           THP_Interface                 4                               //温湿度大气压力显示界面
  5. #define           RTCMenu_Interface             5                               //RTC菜单测试界面
  6. #define           RTCshow_Interface             6                               //RTC实时显示界面
  7. #define           UART_Interface                7                               //串口测试界面


  8. #define           InterfaceOpen                 1                               //其他参数显示界面
  9. #define           InterfaceClose                0                               //其他参数阈值设置界面
  10. typedef struct
  11. {
  12. uint8_t ing; //正在显示的界面
  13. uint8_t Request; //要求显示的界面
  14. }show;      
  15. extern  show    Menu,Menu_unit,LEDTest_unit,RTCMenu_unit;
  按键状态判断及处理:
  1. void App_KEY_Judge(void)
  2. {
  3.   if(key_Ok.ShortPress_flag == 1)//短按OK键
  4.   {
  5.     switch(Menu.ing)
  6.     {
  7.       case Holle_Interface:
  8.         Menu.Request = Menu_Interface;
  9.         Menu_unit.Request = 1;
  10.         break;
  11.         
  12.       case Menu_Interface:
  13.         Menu_unit.Request = PARA_Cyclic(1,5,Menu_unit.Request,1);
  14.         break;
  15.         
  16.       case LEDTest_Interface:
  17.         LEDTest_unit.Request = PARA_Cyclic(1,3,LEDTest_unit.Request,1);
  18.         LED.Mode_Dis = LEDTest_unit.Request;
  19.         break;
  20.         
  21.       case RTCMenu_Interface:
  22.         RTCMenu_unit.Request = PARA_Cyclic(1,4,RTCMenu_unit.Request,1);
  23.         break;
  24.         
  25.       case UART_Interface:
  26.         USART2_sendbits("AT32WB415 USART Test \r\n");
  27.         break;
  28.       
  29.       default:
  30.         break;

  31.     }
  32.     key_Ok.ShortPress_flag = 0;
  33.   }
  34.   
  35.   if(key_Ok.LongPress_flag == 1)//长按OK键
  36.   {
  37.    
  38.     switch(Menu.ing)
  39.     {
  40.       case Holle_Interface:
  41.         Menu.Request = Menu_Interface;
  42.         Menu_unit.Request = 1;
  43.         break;
  44.         
  45.       case Menu_Interface:
  46.         if(Menu_unit.Request == 1)
  47.         {
  48.           Menu.Request = LEDTest_Interface;
  49.           LEDTest_unit.Request = 1;
  50.           LED.Mode_Dis = LEDTest_unit.Request;
  51.         }
  52.         else if(Menu_unit.Request == 2)
  53.         {
  54.           Menu.Request = THP_Interface;
  55.         }
  56.         else if(Menu_unit.Request == 3)
  57.         {
  58.           Menu.Request = UART_Interface;
  59.         }
  60.         else if(Menu_unit.Request == 5)
  61.         {
  62.           Menu.Request = RTCMenu_Interface;
  63.           RTCMenu_unit.Request = 1;
  64.         }
  65.         
  66.         Menu_unit.Request = 0;
  67.         MenuInterface_unit_cut(Menu_unit.ing,Menu_unit.Request);
  68.         Menu_unit.ing = 0;
  69.         break;
  70.         
  71.       case LEDTest_Interface:
  72.         Menu.Request = Menu_Interface;
  73.         Menu_unit.Request = 1;
  74.         
  75.         LEDTest_unit.Request = 0;
  76.         LEDTestface_unit_cut(LEDTest_unit.ing,LEDTest_unit.Request);
  77.         LEDTest_unit.ing = 0;
  78.         LED.Mode_Dis = 0;
  79.         
  80.         break;
  81.         
  82.       case THP_Interface:
  83.         Menu.Request = Menu_Interface;
  84.         Menu_unit.Request = 2;
  85.            
  86.         break;
  87.         
  88.       case RTCMenu_Interface:
  89.         if(RTCMenu_unit.Request == 1)
  90.         {
  91.           Menu.Request = RTCshow_Interface;
  92.           RTCMenu_unit.ing = 0;
  93.         }
  94.         else if(RTCMenu_unit.Request == 2)
  95.         {
  96. //          Menu.Request = THP_Interface;
  97.         }
  98.         else if(RTCMenu_unit.Request == 4)//返回上一级界面
  99.         {
  100.           Menu.Request = Menu_Interface;;
  101.           Menu_unit.Request = 5;
  102.          
  103.           RTCMenu_unit.Request = 0;
  104.           RTCMenuface_unit_cut(RTCMenu_unit.ing,RTCMenu_unit.Request);
  105.           RTCMenu_unit.ing = 0;
  106.         }
  107.            
  108.         break;
  109.         
  110.       case RTCshow_Interface:
  111.         Menu.Request = RTCMenu_Interface;
  112.         
  113.         RTCMenu_unit.ing = 0;
  114.         RTCMenu_unit.Request = 1;
  115.            
  116.         break;
  117.         
  118.       case UART_Interface:
  119.         Menu.Request = Menu_Interface;
  120.         Menu_unit.Request = 3;
  121.            
  122.         break;
  123.       
  124.       default:
  125.         break;

  126.     }

  127.     key_Ok.LongPress_flag = 0;
  128.   }

  129. }
  界面静态切换:
  1. if(Menu.ing != Menu.Request)                                //静态界面切换
  2.   {
  3.     setup(Menu.Request);
  4.   }
  5. void setup(uint8_t FaceNum)
  6. {
  7.   switch(Menu.ing)
  8.   {
  9.     case Holle_Interface:
  10.       HolleInterface(InterfaceClose);
  11.       break;
  12.       
  13.     case Menu_Interface:
  14.       MenuInterface(InterfaceClose);
  15.       break;
  16.       
  17.     case LEDTest_Interface:
  18.       LEDTestface(InterfaceClose);
  19.       break;
  20.       
  21.     case THP_Interface:
  22.       THPInterface(InterfaceClose);
  23.       break;
  24.       
  25.     case RTCMenu_Interface:
  26.       RTCMenuface(InterfaceClose);
  27.       break;
  28.       
  29.     case RTCshow_Interface:
  30.       RTCShowface(InterfaceClose);
  31.       break;
  32.       
  33.     case UART_Interface:
  34.       USARTInterface(InterfaceClose);
  35.       break;
  36.         
  37.     default:
  38.       break;
  39.         
  40.   }
  41.   
  42.   switch(FaceNum)
  43.   {
  44.     case Holle_Interface:
  45.       HolleInterface(InterfaceOpen);
  46.       break;
  47.       
  48.     case Menu_Interface:
  49.       MenuInterface(InterfaceOpen);
  50.       break;
  51.       
  52.     case LEDTest_Interface:
  53.       LEDTestface(InterfaceOpen);
  54.       break;
  55.       
  56.     case THP_Interface:
  57.       THPInterface(InterfaceOpen);
  58.       break;
  59.       
  60.     case RTCMenu_Interface:
  61.       RTCMenuface(InterfaceOpen);
  62.       break;
  63.       
  64.     case RTCshow_Interface:
  65.       RTCShowface(InterfaceOpen);
  66.       break;
  67.       
  68.     case UART_Interface:
  69.       USARTInterface(InterfaceOpen);
  70.       break;

  71.     default:
  72.       break;
  73.         
  74.   }
  75.   
  76.   Menu.ing = FaceNum;
  77.    
  78.   
  79. }
5)接下来就是各个分界面功能的实现,其一:LED操作
  根据需求分析中的解析,其涉及基本定时器、PWM操作,模式切换可以在App_KEY_Judge(void)中进行。
  LED对应IO口初始化:
  1. void LED_GPIO_init(void)
  2. {
  3.   gpio_init_type gpio_init_struct;
  4.   
  5.   crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);/* enable the led clock */
  6.   gpio_default_para_init(&gpio_init_struct);/* set default parameter */

  7.   /* configure the led gpio */
  8.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  9.   gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  10.   gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  11.   gpio_init_struct.gpio_pins = GPIO_PINS_7|GPIO_PINS_8|GPIO_PINS_9;
  12.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  13.   gpio_init(GPIOB, &gpio_init_struct);
  14. }
  IO口操作宏定义:
  1. /************************************宏定义************************************/
  2. #define LEDRed_on               gpio_bits_reset(GPIOB,GPIO_PINS_7);
  3. #define LEDRed_off              gpio_bits_set(GPIOB,GPIO_PINS_7);
  4. #define LEDRed_Toggle           gpio_bits_TogglePin(GPIOB,GPIO_PINS_7);

  5. #define LEDYellow_on            gpio_bits_reset(GPIOB,GPIO_PINS_8);
  6. #define LEDYellow_off           gpio_bits_set(GPIOB,GPIO_PINS_8);
  7. #define LEDYellow_Toggle        gpio_bits_TogglePin(GPIOB,GPIO_PINS_8);

  8. #define LEDGreen_on             gpio_bits_reset(GPIOB,GPIO_PINS_9);
  9. #define LEDGreen_off            gpio_bits_set(GPIOB,GPIO_PINS_9);
  10. #define LEDGreen_Toggle         gpio_bits_TogglePin(GPIOB,GPIO_PINS_9);
  定时器4PWM输出配置:
  1. void Tmr4PWM_init(uint16_t Period)
  2. {
  3.   /* tmr4 clock enable */
  4.   crm_periph_clock_enable(CRM_TMR4_PERIPH_CLOCK, TRUE);
  5.   /* gpioa gpiob clock enable */
  6.   crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
  7.   
  8.   gpio_init_type gpio_init_struct;
  9.   tmr_output_config_type tmr_oc_init_structure;
  10.   
  11.   gpio_default_para_init(&gpio_init_struct);
  12.   gpio_init_struct.gpio_pins = GPIO_PINS_7 | GPIO_PINS_8 | GPIO_PINS_9;
  13.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  14.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  15.   gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  16.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  17.   gpio_init(GPIOB, &gpio_init_struct);
  18.   
  19.   /* tmr4 configuration */
  20.   /* time base configuration */
  21.   /* systemclock/14400/10000 = 1hz */
  22.   tmr_base_init(TMR4, 1000000/Period - 1, 144 - 1);
  23.   tmr_cnt_dir_set(TMR4, TMR_COUNT_UP);
  24.   tmr_clock_source_div_set(TMR4, TMR_CLOCK_DIV1);
  25.   
  26.   tmr_output_default_para_init(&tmr_oc_init_structure);
  27.   tmr_oc_init_structure.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A;
  28.   tmr_oc_init_structure.oc_idle_state = TRUE;
  29.   tmr_oc_init_structure.oc_polarity = TMR_OUTPUT_ACTIVE_LOW;
  30.   tmr_oc_init_structure.oc_output_state = TRUE;

  31.   tmr_output_channel_config(TMR4, TMR_SELECT_CHANNEL_2, &tmr_oc_init_structure);
  32.   tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_2, 0);
  33.   tmr_output_channel_buffer_enable(TMR4, TMR_SELECT_CHANNEL_2, TRUE);

  34.   tmr_output_channel_config(TMR4, TMR_SELECT_CHANNEL_3, &tmr_oc_init_structure);
  35.   tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_3, 0);
  36.   tmr_output_channel_buffer_enable(TMR4, TMR_SELECT_CHANNEL_3, TRUE);

  37.   tmr_output_channel_config(TMR4, TMR_SELECT_CHANNEL_4, &tmr_oc_init_structure);
  38.   tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_4, 0);
  39.   tmr_output_channel_buffer_enable(TMR4, TMR_SELECT_CHANNEL_4, TRUE);

  40.   tmr_period_buffer_enable(TMR4, TRUE);

  41.   /* tmr enable counter */
  42.   tmr_counter_enable(TMR4, TRUE);
  43. }
  定义吸灯的频率设置为2s,并定义了LED控制结构体:
  1. typedef struct
  2. {
  3. uint8_t Mode_Dis; //LED显示模式
  4. uint8_t Mode_OidDis; //LED上一次显示模式
  5. uint8_t PWMcnt; //LED控制模式
  6. uint8_t state; //LED过程
  7. uint8_t UpFlag; //更新标志
  8. uint8_t Upcnt; //更新计时计数
  9. }LED_states;

  10. if(LED.UpFlag == 0)
  11.     {
  12.       if(LED.Mode_Dis == 0 || LED.Mode_Dis == 1)
  13.       {
  14.         LED.Upcnt++;
  15.         if(LED.Upcnt%100 == 0)
  16.         {
  17.           LED.state++;
  18.           LED.state %= 3;
  19.           LED.Upcnt = 0;
  20.           LED.UpFlag = 1;
  21.         }
  22.       }
  23.       else if(LED.Mode_Dis == 2)
  24.       {
  25. //        PWMcnt = Tmr4PWM/10*2;
  26.         LED.Upcnt++;
  27.         if(LED.Upcnt%200 == 0)
  28.         {
  29.           LED.state++;
  30.           LED.state %= 3;
  31.           LED.Upcnt = 0;
  32.           LED.UpFlag = 1;
  33.         }
  34.         if(LED.Upcnt <= 100)
  35.         {
  36.           LED.PWMcnt = LED.Upcnt;
  37.         }
  38.         if(LED.Upcnt <= 200 && LED.Upcnt > 100)
  39.         {
  40.           LED.PWMcnt = 200 - LED.Upcnt;
  41.         }
  42.       }
  43.     }
  LED执行函数:
  1. void App_LED(void)
  2. {
  3.   if(LED.Mode_OidDis != LED.Mode_Dis)
  4.   {
  5.     LED.Upcnt = 0;
  6.     LED.state = 0;
  7.     LED.UpFlag = 1;
  8.    
  9.     if(LED.Mode_OidDis == 2)
  10.     {
  11.       tmr_counter_enable(TMR4, FALSE);
  12.       LED_GPIO_init();
  13.       
  14.     }
  15.     else
  16.     {
  17.       LEDRed_off;
  18.       LEDYellow_off;
  19.       LEDGreen_off;
  20.     }

  21.     switch(LED.Mode_Dis)
  22.     {
  23.       case 0:
  24.         LEDRed_on;
  25.         LEDYellow_on;
  26.         LEDGreen_on;
  27.         break;
  28.         
  29.       case 1:
  30.         LEDRed_on;
  31.         break;
  32.         
  33.       case 2:
  34.         Tmr4PWM_init(Tmr4PWM);
  35.         LED.Upcnt = 0;
  36.         break;

  37.       default:
  38.         break;
  39.     }
  40.     LED.Mode_OidDis = LED.Mode_Dis;
  41.   }
  42.   
  43.   if(LED.UpFlag == 1)
  44.   {
  45.     if(LED.Mode_Dis == 0)
  46.     {
  47.       LEDRed_Toggle;
  48.       LEDYellow_Toggle;
  49.       LEDGreen_Toggle;
  50.     }
  51.     else if(LED.Mode_Dis == 1)
  52.     {
  53.       switch(LED.state)
  54.       {
  55.         case 0:
  56.           LEDRed_on;
  57.           LEDGreen_off;
  58.           break;
  59.          
  60.         case 1:
  61.           LEDRed_Toggle;
  62.           LEDYellow_Toggle;
  63.           break;
  64.          
  65.         case 2:
  66.           LEDYellow_Toggle;
  67.           LEDGreen_Toggle;
  68.           break;
  69.          
  70.         default:
  71.           break;
  72.       }
  73.     }
  74.     else if(LED.Mode_Dis == 2)
  75.     {
  76.       switch(LED.state)
  77.       {
  78.         case 0:
  79.           tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_2, LED.PWMcnt*50);
  80.           break;
  81.          
  82.         case 1:
  83.           tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_3, LED.PWMcnt*50);
  84.           break;
  85.          
  86.         case 2:
  87.           tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_4, LED.PWMcnt*50);
  88.           break;
  89.          
  90.         default:
  91.           break;
  92.       }
  93.     }
  94.     LED.UpFlag = 0;
  95.   }
  96. }
6)AHT20数据获取接AHT界面设计
  其实模拟IIC就是两个引脚的IO状态来模拟时序,通过IO口的高低电平及上升下降沿来完美模拟时序,本开发板对应的IIC接口是PB7和PB6,注意PB7同时是红灯的控制引脚,通过IO口模拟正确读取了数据,不过使用硬件IIC是并没有成功,一直得不到从机的回复,考虑到速度问题,就没有继续进行硬件IIC的实现,也希望大佬可以指导一下雅特力的硬件IIC。
  模拟IIC配置:
  1. #define IIC1_RCU_GPIOB_clock    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE)
  2. #define IIC1_SDA_INITOut        IIC1_SDA_GPIO_OutConfig()
  3. #define IIC1_SDA_INITIn         IIC1_SDA_GPIO_InConfig()
  4. #define IIC1_SDA_SET            gpio_bits_set(GPIOB,GPIO_PINS_7)                  
  5. #define IIC1_SDA_RESET          gpio_bits_reset(GPIOB,GPIO_PINS_7)
  6. #define IIC1_ReadSDA            gpio_input_data_bit_read(GPIOB, GPIO_PINS_7)

  7. #define IIC1_SCL_INITOut        IIC1_SCL_GPIO_OutConfig()
  8. #define IIC1_SCL_SET            gpio_bits_set(GPIOB,GPIO_PINS_6)                  
  9. #define IIC1_SCL_RESET          gpio_bits_reset(GPIOB,GPIO_PINS_6)

  10. void IIC1_IOInit(void)
  11. {
  12.   gpio_init_type gpio_init_struct;
  13.   IIC1_RCU_GPIOB_clock;
  14.   
  15.   gpio_default_para_init(&gpio_init_struct);

  16.   gpio_init_struct.gpio_drive_strength  = GPIO_DRIVE_STRENGTH_MAXIMUM;
  17.   gpio_init_struct.gpio_out_type        = GPIO_OUTPUT_PUSH_PULL;
  18.   gpio_init_struct.gpio_mode            = GPIO_MODE_OUTPUT;
  19.   gpio_init_struct.gpio_pins            = GPIO_PINS_6|GPIO_PINS_7;
  20.   gpio_init_struct.gpio_pull            = GPIO_PULL_UP;
  21.   gpio_init(GPIOB, &gpio_init_struct);
  22.   
  23.   IIC1_SDA_SET;
  24.   IIC1_SCL_SET;

  25. }

  26. void IIC1_SDA_GPIO_OutConfig(void)
  27. {
  28.   gpio_init_type gpio_init_struct;
  29.   IIC1_RCU_GPIOB_clock;

  30.   gpio_default_para_init(&gpio_init_struct);
  31.   gpio_init_struct.gpio_drive_strength  = GPIO_DRIVE_STRENGTH_MAXIMUM;
  32.   gpio_init_struct.gpio_out_type        = GPIO_OUTPUT_PUSH_PULL;
  33.   gpio_init_struct.gpio_mode            = GPIO_MODE_OUTPUT;
  34.   gpio_init_struct.gpio_pins            = GPIO_PINS_7;
  35.   gpio_init_struct.gpio_pull            = GPIO_PULL_UP;
  36.   gpio_init(GPIOB, &gpio_init_struct);
  37. }

  38. void IIC1_SDA_GPIO_InConfig(void)
  39. {
  40.   gpio_init_type gpio_init_struct;
  41.   IIC1_RCU_GPIOB_clock;

  42.   gpio_default_para_init(&gpio_init_struct);
  43.   gpio_init_struct.gpio_mode            = GPIO_MODE_INPUT;
  44.   gpio_init_struct.gpio_pins            = GPIO_PINS_7;
  45.   gpio_init_struct.gpio_pull            = GPIO_PULL_NONE;
  46.   gpio_init(GPIOB, &gpio_init_struct);
  47. }

  48. void IIC1_SCL_GPIO_OutConfig(void)
  49. {
  50.   gpio_init_type gpio_init_struct;
  51.   IIC1_RCU_GPIOB_clock;

  52.   gpio_default_para_init(&gpio_init_struct);
  53.   gpio_init_struct.gpio_drive_strength  = GPIO_DRIVE_STRENGTH_MAXIMUM;
  54.   gpio_init_struct.gpio_out_type        = GPIO_OUTPUT_PUSH_PULL;
  55.   gpio_init_struct.gpio_mode            = GPIO_MODE_OUTPUT;
  56.   gpio_init_struct.gpio_pins            = GPIO_PINS_6;
  57.   gpio_init_struct.gpio_pull            = GPIO_PULL_UP;
  58.   gpio_init(GPIOB, &gpio_init_struct);
  59. }

  60. void IIC1_IIC_Init(void)
  61. {
  62.   IIC1_SDA_INITOut;
  63. //  IIC1_IIC_Stop();
  64.   IIC1_SDA_RESET;
  65.   IIC1_SCL_RESET;
  66. }

  67. void IIC1_IIC_Start(void)
  68. {
  69.   IIC1_SDA_SET;
  70.   delay_us(8);
  71.   IIC1_SCL_SET;
  72.   delay_us(14);
  73.   IIC1_SDA_RESET;
  74.   delay_us(14);
  75.   IIC1_SCL_RESET;
  76.   delay_us(14);
  77. }

  78. void IIC1_IIC_Stop(void)
  79. {
  80.   IIC1_SDA_RESET;
  81.   delay_us(14);
  82.   IIC1_SCL_SET;
  83.   delay_us(8);
  84.   IIC1_SDA_SET;
  85.   delay_us(14);
  86. }
  1. void IIC1_SendACK(uint8_t ack)  
  2. {
  3.   IIC1_SDA_INITOut;
  4.   if(ack == 0)
  5.   IIC1_SDA_RESET;                                                              //写应答信号
  6.   else
  7.   IIC1_SDA_SET;  
  8.   delay_us(14);
  9.   IIC1_SCL_SET;                                                                //拉高时钟线  
  10.   delay_us(14);                                                           //延时  
  11.   IIC1_SCL_RESET;                                                              //拉低时钟线  
  12.   delay_us(14);                                                           //延时   
  13. }

  14. uint8_t IIC1_RecvACK(void)  
  15. {  
  16.   
  17.   uint8_t RecvACK;
  18.    
  19.   IIC1_SDA_INITIn;                                                    //SDA接口为输入
  20.   delay_us(8);
  21.   IIC1_SCL_SET;                                                                //拉高时钟线  
  22.   delay_us(8);                                                           //延时  
  23.   RecvACK = IIC1_ReadSDA;                                                      //读应答信号  
  24.   IIC1_SCL_RESET;                                                              //拉低时钟线  
  25.   delay_us(8);                                                           //延时
  26.   IIC1_SDA_INITOut;
  27.    
  28.   return RecvACK;
  29.    
  30. }

  31. uint8_t IIC1_SendByte(uint8_t dat)  
  32. {  
  33.   uint8_t datsendbit;
  34.   uint8_t RecvACK;
  35.    
  36.   for (uint8_t i=0; i<8; i++)                                                   //8位计数器  
  37.   {  
  38.     datsendbit = ((dat & 0x80) >> 7);
  39.     dat <<= 1;                                                                  //移出数据的最高位
  40.     if(datsendbit == 1)
  41.     {
  42.       IIC1_SDA_SET;
  43.     }
  44.     if(datsendbit == 0)
  45.     {
  46.       IIC1_SDA_RESET;
  47.     }                                                                           //送数据口
  48.     delay_us(8);
  49.     IIC1_SCL_SET;                                                               //拉高时钟线  
  50.     delay_us(8);                                                                //延时  
  51.     IIC1_SCL_RESET;                                                             //拉低时钟线
  52.     delay_us(8);  
  53.   }
  54.   RecvACK = IIC1_RecvACK();
  55.   return RecvACK;  
  56. }

  57. uint8_t IIC1_RecvByte(void)  
  58. {   
  59.   uint8_t RecvDat = 0;
  60.   
  61.   IIC1_SDA_INITIn;
  62.   for (uint8_t i=0; i<8; i++)                                                   //8位计数器  
  63.   {  
  64.     RecvDat <<= 1;
  65.     IIC1_SCL_SET;                                                               //拉高时钟线  
  66.     delay_us(10);                                                               //延时
  67.     RecvDat |= (IIC1_ReadSDA);
  68.     IIC1_SCL_RESET;                                                             //拉低时钟线  
  69.     delay_us(10);                                                               //延时   
  70.   }
  71.   IIC1_SDA_INITOut;
  72.   return RecvDat;
  73.       
  74. }

  75. void IIC1_SendBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr)  
  76. {  
  77.   uint8_t ack = 0;
  78.   IIC1_IIC_Start();
  79.   IIC1_SendByte(dev_addr<<1);
  80.   
  81.   for(uint8_t i = 0; i < len; i++)
  82.   {
  83.     ack = IIC1_SendByte(*(dat+i));
  84.   }
  85.   IIC1_IIC_Stop();
  86. }

  87. void IIC1_RecvBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr)
  88. {  
  89.   IIC1_IIC_Start();
  90.   IIC1_SendByte((dev_addr<<1)+1);
  91.   
  92.   for(uint8_t i = 0; i < len; i++)
  93.   {
  94.     *(dat+i) = IIC1_RecvByte();
  95.    
  96.     if(i == (len - 1))
  97.     {
  98.       IIC1_SendACK(1);
  99.     }
  100.     else
  101.     {
  102.       IIC1_SendACK(0);
  103.     }
  104.   }
  105.   IIC1_IIC_Stop();
  106. }
  AHT20的驱动函数在文章末尾,具体的驱动就不赘述了,定时采集传感器数据并刷新显示;
7)ERTC的实现
  雅特力开发板的RTC又名ERTC,其作用是提供日历管理,因为其计数逻辑作用在电池供电域,因此只要电池供电域有电,ERTC 就不会受到系统复位以及VDD掉电影响。不过开发板是不带电池域单独供电的。ERTC的ck_b用于更新日历,开发板包含外部32.768kHz时钟,首选通过LEXT经过分频器A 和分频器B获得,ck_b=LEXT/(divA+1)/(divB+1),例如32.768K的时钟通过A分频器127、B分频器255,获得1Hz频率。上电复位后所有ERTC 寄存器都处于写保护状态,在进行擦写前一定要先解除写保护,这部分和多数MCU的配置过程基本是相同的,解除写保护——写配置——写保护,部分寄存器需要进入初始化模式才能更改。ERTC的时间寄存器和日期寄存器就是需要经常访问的寄存器,更新日历就是直接更新这两个寄存器,这一点与GD32F303的单片机略有不同,GD实际上是一个64位的寄存器,只存一个自增数,具体的时间设定还需要自己去进行设计,这里可以直接访问时间相关寄存器,更像一个外部的实时时钟模式,直接获取年月日时分秒,不过ERTC的可统计时间范围没有给出,润年机制方面也没有什么介绍,寄存器中的年份只有十位和各位。
  ERTC初始化:
  1. void ertc_config(void)
  2. {
  3.   /* allow access to ertc */
  4.   pwc_battery_powered_domain_access(TRUE);
  5.   /* reset ertc domain */
  6.   crm_battery_powered_domain_reset(TRUE);
  7.   crm_battery_powered_domain_reset(FALSE);
  8.   /* enable the lext osc */
  9.   crm_clock_source_enable(CRM_CLOCK_SOURCE_LEXT, TRUE);
  10.   /* wait till lext is ready */
  11.   while(crm_flag_get(CRM_LEXT_STABLE_FLAG) == RESET)
  12.   {
  13.   }
  14.   /* select the ertc clock source */
  15.   crm_ertc_clock_select(CRM_ERTC_CLOCK_LEXT);
  16.   /* enable the ertc clock */
  17.   crm_ertc_clock_enable(TRUE);

  18.   /* deinitializes the ertc registers */
  19.   ertc_reset();
  20.   /* wait for ertc apb registers update */
  21.   ertc_wait_update();
  22.   
  23.   /* configure the ertc divider */
  24.   /* ertc second(1hz) = ertc_clk / (div_a + 1) * (div_b + 1) */
  25.   ertc_divider_set(127, 255);
  26.   /* configure the ertc hour mode */
  27.   ertc_hour_mode_set(ERTC_HOUR_MODE_24);

  28.   eRTC_set.year     = 22;
  29.   eRTC_set.month    = 8;
  30.   eRTC_set.day      = 18;
  31.   eRTC_set.hour     = 8;
  32.   eRTC_set.min      = 0;
  33.   eRTC_set.sec      = 0;
  34.   eRTC_set.week     = 4;
  35.   Set_Time(&eRTC_set);
  36. }
  应用函数:
  1. void Set_Time(ertc_time_type* time)
  2. {
  3.   /* set date  */
  4.   ertc_date_set(time->year,time->month,time->day,time->week);
  5.   /* set time*/
  6.   ertc_time_set(time->hour,time->min,time->sec,ERTC_AM);
  7. }

  8. uint32_t bpr_reg_get(uint8_t index)
  9. {
  10.   if(index >= ERTC_BPR_DT_NUMBER)
  11.   {
  12.     index = 0;
  13.   }
  14.   return ertc_bpr_data_read(bpr_addr_tab[index]);
  15. }

  16. void bpr_reg_write(uint8_t index,uint32_t DT_data)
  17. {
  18.   ertc_bpr_data_write(bpr_addr_tab[index],DT_data);
  19. }
  这里比较遗憾的是按键的限制导致不太好设计设置时间的部分,不过这部分在串口通信中得到了解决。
8)串口通信
  串口1对应的引脚与IIC冲突,所以对PC的通信只能使用串口2了,串口3是对蓝牙的通信,固定死的。
  串口2配置:
  1. void USART2_init(void)
  2. {
  3.   gpio_init_type gpio_init_struct;
  4.   /* enable the usart2 and gpio clock */
  5.   crm_periph_clock_enable(CRM_USART2_PERIPH_CLOCK, TRUE);
  6.   crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  7.   
  8.   /* enable iomux clock */
  9.   crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
  10.   
  11.   gpio_default_para_init(&gpio_init_struct);

  12.   /* configure the usart2 tx pin */
  13.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  14.   gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  15.   gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  16.   gpio_init_struct.gpio_pins = GPIO_PINS_2;
  17.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  18.   gpio_init(GPIOA, &gpio_init_struct);
  19.   
  20.   /* configure the usart2 rx pin */
  21.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  22.   gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  23.   gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  24.   gpio_init_struct.gpio_pins = GPIO_PINS_3;
  25.   gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  26.   gpio_init(GPIOA, &gpio_init_struct);
  27.   
  28.   /* config usart nvic interrupt */
  29.   nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  30.   nvic_irq_enable(USART2_IRQn, 0, 0);
  31.   
  32.   /* configure usart2 param */
  33.   usart_init(USART2, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);
  34.   usart_transmitter_enable(USART2, TRUE);
  35.   usart_receiver_enable(USART2, TRUE);
  36.   
  37.   /* enable usart2 interrupt */
  38.   usart_interrupt_enable(USART2, USART_RDBF_INT, TRUE);
  39.   usart_enable(USART2, TRUE);

  40.   
  41. }
  采用的方式是中断接受数据,非中断方式发送数据,发送和接收处理函数如下:
  1. //******************************************************************************
  2. //* 函数名称  : USART_sendbit(TxBuffer)
  3. //* 函数描述  : 串口发送一个字节
  4. //* 输入参数  :
  5. //* 参数描述  :  TxBuffer:存储发送的一个字节
  6. //* 输出参数  : 无
  7. //* 返回值    : 无
  8. //******************************************************************************   
  9. void USART2_sendbit(uint8_t aaTx)
  10. {
  11.   usart_data_transmit(USART2,aaTx);
  12.   while((usart_flag_get(USART2, USART_TDBE_FLAG) == RESET));
  13. }

  14. //******************************************************************************
  15. //* 函数名称  : USART_sendbit(TxBuffer)
  16. //* 函数描述  : 串口发送多个字节
  17. //* 输入参数  :
  18. //* 参数描述  :  TxBuffer:存储发送的一个字节
  19. //* 输出参数  : 无
  20. //* 返回值    : 无
  21. //******************************************************************************   
  22. void USART2_sendbits(uint8_t *HzpAscii)
  23. {
  24.   while(*HzpAscii != 0)
  25.   {
  26.     usart_data_transmit(USART2,*HzpAscii);
  27.     while((usart_flag_get(USART2, USART_TDBE_FLAG) == RESET));
  28.     HzpAscii += 1;
  29.   }
  30.   
  31. }
  32. //******************************************************************************
  33. // 函数名称  : USART2_deal
  34. // 函数描述  : 串口中断处理
  35. // 输入参数  :
  36. // 参数描述  : 无
  37. // 输出参数  : 无
  38. // 返回值    : 无
  39. //******************************************************************************
  40. void USART2_deal(uint8_t USART_data)
  41. {
  42.   
  43.   uint8_t check = 0;
  44.   
  45.   if(USART_data == 0xA5 && Com_Data.ing_step == 0)
  46.   {
  47.     Com_Data.STX_1 = 0xA5;
  48.     Com_Data.ing_step = 1;
  49.   }
  50.   else if(USART_data == 0x5A && Com_Data.ing_step == 1)
  51.   {
  52.     Com_Data.STX_2 = 0x5A;
  53.     Com_Data.ing_step = 2;
  54.   }
  55.   else if(Com_Data.ing_step == 2)
  56.   {
  57.     Com_Data.Length = USART_data;
  58.     Com_Data.ing_step = 3;
  59.   }
  60.   else if(Com_Data.ing_step == 3)
  61.   {
  62.     RecePackBuf[Com_Data.ReturnCnt] = USART_data;
  63.     Com_Data.ReturnCnt ++;
  64.     if(Com_Data.Length == Com_Data.ReturnCnt)
  65.     {
  66.       Com_Data.CHECKSUM_1 = RecePackBuf[Com_Data.ReturnCnt-1];
  67.       for(uint8_t i=0;i<Com_Data.Length-1;i++)
  68.       {
  69.         check += RecePackBuf[i];
  70.       }
  71.       if(Com_Data.CHECKSUM_1 = check)//校验成功
  72.       {
  73.         line_** = 2;
  74.         Com_Data.CMD = RecePackBuf[0];
  75.       }
  76.       else
  77.       {
  78.         memset(RecePackBuf, 0,ARRAYNUM(RecePackBuf));//清空接收包
  79.         memset(&Com_Data,0,sizeof(Com_Data));//清空结构体
  80.       }
  81.     }
  82.   }
  83.   else
  84.   {
  85.     memset(RecePackBuf, 0,ARRAYNUM(RecePackBuf));//清空接收包
  86.     memset(&Com_Data,0,sizeof(Com_Data));//清空结构体
  87.   }
  88. }
  对于接收具体处理,这边采用的是通信协议的方式进行甄别,实现方式千千万,只取适合自己的那一瓢,这时候就可以把设置时间放到了这里,同时也可以控制LED的显示,只要正确解析就可以。
9)蓝牙通信
  其实所谓蓝牙通信实现的功能就是串口通信的无线化,其透传模式功能实现的就是串口通信的延伸,命令模式就是对蓝牙模块的配置。本开发板通过串口3和蓝牙模块的耦合实现芯片自带的蓝牙功能。最开始测试想把开发板作为主机进行扫描的,不过通过对资料的分析,这个工程有点大,本次测试提供的资料里只有简单的AT指令,所以改变目标,实现基本透传功能。
  串口3使用的是空闲中断+DMA的方式进行的,这样可以减少串口中断的次数,蓝牙切换为透传模式也是非常方便的,发送"AT+TPMODE1\r\n"就可以。
  串口三初始化:
  1. void USART3_init(void)
  2. {
  3.   gpio_init_type gpio_init_struct;
  4.   
  5.   crm_periph_clock_enable(CRM_USART3_PERIPH_CLOCK, TRUE);
  6.   crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);  
  7.   crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
  8.   
  9.   gpio_pin_remap_config(USART3_GMUX_0010, TRUE);
  10.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  11.   gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  12.   gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  13.   gpio_init_struct.gpio_pins = GPIO_PINS_7;
  14.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  15.   gpio_init(GPIOA, &gpio_init_struct);
  16.   
  17.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  18.   gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  19.   gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  20.   gpio_init_struct.gpio_pins = GPIO_PINS_6;
  21.   gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  22.   gpio_init(GPIOA, &gpio_init_struct);
  23.   
  24.   usart_init(USART3, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);
  25.   usart_transmitter_enable(USART3, TRUE);
  26.   usart_receiver_enable(USART3, TRUE);
  27.   usart_dma_receiver_enable(USART3, TRUE);
  28.   
  29.   USART3_DMA1_config();

  30.   nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  31.   nvic_irq_enable(USART3_IRQn, 0, 0);
  32.   /* Enable the USARTx Interrupt */
  33.   usart_interrupt_enable(USART3, USART_IDLE_INT, TRUE);
  34. //  usart_interrupt_enable(USART3, USART_RDBF_INT, TRUE);
  35.   usart_enable(USART3, TRUE);
  36.   
  37. }
DMA初始化:
  1. void USART3_DMA1_config(void)
  2. {
  3.   dma_init_type dma_init_struct;

  4.   /* enable dma1 clock */
  5.   crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);

  6.   /* dma1 channel3 for usart1 tx configuration */
  7.   dma_reset(DMA1_CHANNEL3);
  8.   dma_default_para_init(&dma_init_struct);
  9.   dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;//外设到内存
  10.   dma_init_struct.memory_base_addr = (uint32_t)USART3RecePackBuf;//内存接收基地址
  11.   dma_init_struct.memory_inc_enable = TRUE;//内存地址递增
  12.   dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;//8位数据
  13.   dma_init_struct.buffer_size = ARRAYNUM(USART3RecePackBuf);
  14.   
  15.   dma_init_struct.peripheral_base_addr = (uint32_t)&USART3->dt;//外设地址
  16.   dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;//外设数据长度
  17.   dma_init_struct.peripheral_inc_enable = FALSE;//外设地址不增加
  18.   dma_init_struct.priority = DMA_PRIORITY_MEDIUM;//最高DMA通道
  19.   dma_init_struct.loop_mode_enable = TRUE;
  20.   dma_init(DMA1_CHANNEL3, &dma_init_struct);

  21.   /* config flexible dma for usart3 Rx */
  22.   dma_flexible_config(DMA1, FLEX_CHANNEL3, DMA_FLEXIBLE_UART3_RX);

  23.   dma_channel_enable(DMA1_CHANNEL3, TRUE); /* usart1 tx begin dma transmitting */
  24. }
这里我们将DMA初始化单独拎出来,是为了实现串口处理函数中对DMA重新进行配置。
  串口处理函数:
  1. void USART3_DMA_deal(void)
  2. {
  3.   uint8_t ReturnCnt;
  4.   uint8_t check = 0;
  5.   dma_channel_enable(DMA1_CHANNEL3, FALSE);                                        /* 关闭DMA传输 */

  6.   ReturnCnt = ARRAYNUM(USART3RecePackBuf)-dma_data_number_get(DMA1_CHANNEL3);
  7.   memcpy(BLEPackBuf,USART3RecePackBuf,ReturnCnt);
  8.   memset(USART3RecePackBuf, 0,ReturnCnt);//清空接收包
  9.   
  10. //  usart_data_transmit(USART0, RecePackBuf[0]);
  11. //  while((usart_flag_get(USART0, USART_FLAG_TBE) == RESET));
  12.   if(BLEPackBuf[0] == 0xA5 && BLEPackBuf[1] == 0x5A)
  13.   {
  14.     Com_Data.Length     = BLEPackBuf[2];
  15.     Com_Data.CHECKSUM_1 = BLEPackBuf[ReturnCnt-1];
  16.    
  17.     for(uint8_t i=0;i<Com_Data.Length-1;i++)
  18.     {
  19.       check += BLEPackBuf[i+3];
  20.     }
  21.     if(Com_Data.CHECKSUM_1 = check)//校验成功
  22.     {
  23.       line_** = 3;
  24.       memcpy(RecePackBuf,BLEPackBuf+3,ReturnCnt-4);
  25.       Com_Data.CMD = RecePackBuf[0];
  26.       memset(BLEPackBuf, 0,Com_Data.Length+3);//清空接收包
  27.     }
  28.     else
  29.     {
  30.       memset(BLEPackBuf, 0,ARRAYNUM(BLEPackBuf));//清空接收包
  31.       memset(&Com_Data,0,sizeof(Com_Data));//清空结构体
  32.     }
  33.    
  34.    
  35.   }

  36.   USART3_DMA1_config();
  37. }
这里一共用到了三个数组,实现对接收数据的隔离及缓存,我们在进入空闲中断是需要关闭DMA通道,避免这个是后继续接收数据,重新调用USART3_DMA1_config();而不是简单的开启DMA通道的目的是使下一组数据依然从0开始,而不是接着上一个数据存储。通过memcpy(RecePackBuf,BLEPackBuf+3,ReturnCnt-4);使数据与串口解析数据进行融合,共用同一个解析程序。
10)总结
  AT32WB415是一个非常优秀全面的芯片,是一个面向低功耗消费电子的一款产品,基本可以满足一个产品从控制到显示及通信等多方面要求。不过也有一些不足,例如内部RTC的润年识别机制应该是没有,蓝牙方面控制资料略有不足,建议添加全面的蓝牙设计指南,当然我们对于蓝牙的深层理解还是不够的,还需要继续努力,全面的开发设计资料也是我们所需要的,希望可以补足全面蓝牙设计资料。
  再次感谢论坛和雅特力的这次活动,希望有机会能实际使用该产品进行设计,也希望国产芯片能大踏步发展!











打赏榜单

ArterySW 打赏了 20.00 元 2022-09-14
理由:评测很详细,支持一下。

muyichuan2012 发表于 2022-9-14 17:48 | 显示全部楼层
本帖最后由 muyichuan2012 于 2022-9-14 17:51 编辑

感谢楼主分享详细过程,以下信息作为补充
1 关于ERTC ,以下链接有使用指南
另外,ERTC是有闰年处理机制的,硬件自动处理的。
https://www.arterytek.com/download/APNOTE/AN0047_AT32_ERTC_Application_Note_ZH_V2.0.0.pdf

2 “不过只能分频到144M”
可以的,可使用时钟配置工具进行配置,然后生成相关code.
链接如下:
https://www.arterytek.com/downlo ... uration_V3.0.03.zip






评论

年的存储是一个8位的数,没看到闰年的判断机制介绍,它默认是2000开始吗?  发表于 2022-9-14 21:29
骑着蜗牛狂奔O 发表于 2022-9-15 13:57 | 显示全部楼层
闰年28、29天、月份30、31天,ERTC计数器内部已经处理好了,所以不需要关心,年份设置成4的倍数就是润年,例如0、4、8,你可以设置这些年份,把时间设置成2月,然后就可以观察2月份的天数

评论

年份是一个8位数,也就是或最多可以设置2000到2255年?我的理解对吗,如果是这样的话我就能理解了  发表于 2022-9-15 17:09
xu@xupt 发表于 2022-12-11 00:20 | 显示全部楼层
很详细的教程,感谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:硬件工程师
简介:有着多年硬件开发经验的专业人员,专注于医疗电子领域,热衷于对新鲜事物的探索,喜欢DIY!

556

主题

2718

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部
认证:硬件工程师
简介:有着多年硬件开发经验的专业人员,专注于医疗电子领域,热衷于对新鲜事物的探索,喜欢DIY!

556

主题

2718

帖子

12

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