发新帖本帖赏金 20.00元(功能说明)我要提问
返回列表
打印
[活动专区]

【AT-START-WB415测评】综合测试

[复制链接]
1199|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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和按键,基本就能满足本次测试需要。
  初步的需求分析思维导图:

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

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

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

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

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

  crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

  gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE0);

  exint_default_para_init(&exint_init_struct);
  exint_init_struct.line_enable = TRUE;
  exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
  exint_init_struct.line_select = EXINT_LINE_0;
  exint_init_struct.line_polarity = EXINT_TRIGGER_RISING_EDGE;
  exint_init(&exint_init_struct);

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

#define TFT_RS_reset            gpio_bits_reset(GPIOA,GPIO_PINS_5)
#define TFT_RS_set              gpio_bits_set(GPIOA,GPIO_PINS_5)
#define TFT_RESET_reset         gpio_bits_reset(GPIOA,GPIO_PINS_3)
#define TFT_RESET_set           gpio_bits_set(GPIOA,GPIO_PINS_3)
#define TFT_BL_SET              gpio_bits_set(GPIOA,GPIO_PINS_2)
#define TFT_BL_RESET            gpio_bits_reset(GPIOA,GPIO_PINS_2)
void SPI_IOInit(void)
{
  gpio_init_type gpio_initstructure;
  spi_init_type spi_init_struct;

  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
  
  /* software cs, pa4 as a general io to control flash cs */
  gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  gpio_initstructure.gpio_pull           = GPIO_PULL_UP;
  gpio_initstructure.gpio_mode           = GPIO_MODE_OUTPUT;
  gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_initstructure.gpio_pins           = GPIO_PINS_4|GPIO_PINS_5|GPIO_PINS_3;
  gpio_init(GPIOA, &gpio_initstructure);
  
  gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  gpio_initstructure.gpio_mode           = GPIO_MODE_OUTPUT;
  gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_initstructure.gpio_pull           = GPIO_PULL_DOWN;
  gpio_initstructure.gpio_pins           = GPIO_PINS_2;
  gpio_init(GPIOA, &gpio_initstructure);
  
  CS_OUT0;
  TFT_RS_reset;
  TFT_RESET_reset;
  TFT_BL_RESET;
  /* sck */
  gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
  gpio_initstructure.gpio_pull           = GPIO_PULL_UP;
  gpio_initstructure.gpio_mode           = GPIO_MODE_MUX;
  gpio_initstructure.gpio_pins           = GPIO_PINS_13;
  gpio_init(GPIOB, &gpio_initstructure);
  /* mosi */
  gpio_initstructure.gpio_pull           = GPIO_PULL_DOWN;
  gpio_initstructure.gpio_mode           = GPIO_MODE_MUX;
  gpio_initstructure.gpio_pins           = GPIO_PINS_15;
  gpio_init(GPIOB, &gpio_initstructure);

  crm_periph_clock_enable(CRM_SPI2_PERIPH_CLOCK, TRUE);
  spi_default_para_init(&spi_init_struct);
  spi_init_struct.transmission_mode     = SPI_TRANSMIT_FULL_DUPLEX;
  spi_init_struct.master_slave_mode     = SPI_MODE_MASTER;
  spi_init_struct.mclk_freq_division    = SPI_MCLK_DIV_8;
  spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;
  spi_init_struct.frame_bit_num         = SPI_FRAME_8BIT;
  spi_init_struct.clock_polarity        = SPI_CLOCK_POLARITY_HIGH;
  spi_init_struct.clock_phase           = SPI_CLOCK_PHASE_2EDGE;
  spi_init_struct.cs_mode_selection     = SPI_CS_SOFTWARE_MODE;
  spi_init(SPI2, &spi_init_struct);
  spi_enable(SPI2, TRUE);
}

void SPI_Send_Data(uint8_t Data)
{
  
  CS_OUT0;                                                              //选中该从机
  delay_us(1);
  
  spi_i2s_data_transmit(SPI2, Data);
  while(spi_i2s_flag_get(SPI2, SPI_I2S_TDBE_FLAG) == RESET);
  
  delay_us(1);
  CS_OUT1;                                                            

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


#define           InterfaceOpen                 1                               //其他参数显示界面
#define           InterfaceClose                0                               //其他参数阈值设置界面
typedef struct
{
uint8_t ing; //正在显示的界面
uint8_t Request; //要求显示的界面
}show;      
extern  show    Menu,Menu_unit,LEDTest_unit,RTCMenu_unit;
  按键状态判断及处理:
void App_KEY_Judge(void)
{
  if(key_Ok.ShortPress_flag == 1)//短按OK键
  {
    switch(Menu.ing)
    {
      case Holle_Interface:
        Menu.Request = Menu_Interface;
        Menu_unit.Request = 1;
        break;
        
      case Menu_Interface:
        Menu_unit.Request = PARA_Cyclic(1,5,Menu_unit.Request,1);
        break;
        
      case LEDTest_Interface:
        LEDTest_unit.Request = PARA_Cyclic(1,3,LEDTest_unit.Request,1);
        LED.Mode_Dis = LEDTest_unit.Request;
        break;
        
      case RTCMenu_Interface:
        RTCMenu_unit.Request = PARA_Cyclic(1,4,RTCMenu_unit.Request,1);
        break;
        
      case UART_Interface:
        USART2_sendbits("AT32WB415 USART Test \r\n");
        break;
      
      default:
        break;

    }
    key_Ok.ShortPress_flag = 0;
  }
  
  if(key_Ok.LongPress_flag == 1)//长按OK键
  {
   
    switch(Menu.ing)
    {
      case Holle_Interface:
        Menu.Request = Menu_Interface;
        Menu_unit.Request = 1;
        break;
        
      case Menu_Interface:
        if(Menu_unit.Request == 1)
        {
          Menu.Request = LEDTest_Interface;
          LEDTest_unit.Request = 1;
          LED.Mode_Dis = LEDTest_unit.Request;
        }
        else if(Menu_unit.Request == 2)
        {
          Menu.Request = THP_Interface;
        }
        else if(Menu_unit.Request == 3)
        {
          Menu.Request = UART_Interface;
        }
        else if(Menu_unit.Request == 5)
        {
          Menu.Request = RTCMenu_Interface;
          RTCMenu_unit.Request = 1;
        }
        
        Menu_unit.Request = 0;
        MenuInterface_unit_cut(Menu_unit.ing,Menu_unit.Request);
        Menu_unit.ing = 0;
        break;
        
      case LEDTest_Interface:
        Menu.Request = Menu_Interface;
        Menu_unit.Request = 1;
        
        LEDTest_unit.Request = 0;
        LEDTestface_unit_cut(LEDTest_unit.ing,LEDTest_unit.Request);
        LEDTest_unit.ing = 0;
        LED.Mode_Dis = 0;
        
        break;
        
      case THP_Interface:
        Menu.Request = Menu_Interface;
        Menu_unit.Request = 2;
           
        break;
        
      case RTCMenu_Interface:
        if(RTCMenu_unit.Request == 1)
        {
          Menu.Request = RTCshow_Interface;
          RTCMenu_unit.ing = 0;
        }
        else if(RTCMenu_unit.Request == 2)
        {
//          Menu.Request = THP_Interface;
        }
        else if(RTCMenu_unit.Request == 4)//返回上一级界面
        {
          Menu.Request = Menu_Interface;;
          Menu_unit.Request = 5;
         
          RTCMenu_unit.Request = 0;
          RTCMenuface_unit_cut(RTCMenu_unit.ing,RTCMenu_unit.Request);
          RTCMenu_unit.ing = 0;
        }
           
        break;
        
      case RTCshow_Interface:
        Menu.Request = RTCMenu_Interface;
        
        RTCMenu_unit.ing = 0;
        RTCMenu_unit.Request = 1;
           
        break;
        
      case UART_Interface:
        Menu.Request = Menu_Interface;
        Menu_unit.Request = 3;
           
        break;
      
      default:
        break;

    }

    key_Ok.LongPress_flag = 0;
  }

}
  界面静态切换:
if(Menu.ing != Menu.Request)                                //静态界面切换
  {
    setup(Menu.Request);
  }
void setup(uint8_t FaceNum)
{
  switch(Menu.ing)
  {
    case Holle_Interface:
      HolleInterface(InterfaceClose);
      break;
      
    case Menu_Interface:
      MenuInterface(InterfaceClose);
      break;
      
    case LEDTest_Interface:
      LEDTestface(InterfaceClose);
      break;
      
    case THP_Interface:
      THPInterface(InterfaceClose);
      break;
      
    case RTCMenu_Interface:
      RTCMenuface(InterfaceClose);
      break;
      
    case RTCshow_Interface:
      RTCShowface(InterfaceClose);
      break;
      
    case UART_Interface:
      USARTInterface(InterfaceClose);
      break;
        
    default:
      break;
        
  }
  
  switch(FaceNum)
  {
    case Holle_Interface:
      HolleInterface(InterfaceOpen);
      break;
      
    case Menu_Interface:
      MenuInterface(InterfaceOpen);
      break;
      
    case LEDTest_Interface:
      LEDTestface(InterfaceOpen);
      break;
      
    case THP_Interface:
      THPInterface(InterfaceOpen);
      break;
      
    case RTCMenu_Interface:
      RTCMenuface(InterfaceOpen);
      break;
      
    case RTCshow_Interface:
      RTCShowface(InterfaceOpen);
      break;
      
    case UART_Interface:
      USARTInterface(InterfaceOpen);
      break;

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

  /* configure the led gpio */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  gpio_init_struct.gpio_pins = GPIO_PINS_7|GPIO_PINS_8|GPIO_PINS_9;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init(GPIOB, &gpio_init_struct);
}
  IO口操作宏定义:
/************************************宏定义************************************/
#define LEDRed_on               gpio_bits_reset(GPIOB,GPIO_PINS_7);
#define LEDRed_off              gpio_bits_set(GPIOB,GPIO_PINS_7);
#define LEDRed_Toggle           gpio_bits_TogglePin(GPIOB,GPIO_PINS_7);

#define LEDYellow_on            gpio_bits_reset(GPIOB,GPIO_PINS_8);
#define LEDYellow_off           gpio_bits_set(GPIOB,GPIO_PINS_8);
#define LEDYellow_Toggle        gpio_bits_TogglePin(GPIOB,GPIO_PINS_8);

#define LEDGreen_on             gpio_bits_reset(GPIOB,GPIO_PINS_9);
#define LEDGreen_off            gpio_bits_set(GPIOB,GPIO_PINS_9);
#define LEDGreen_Toggle         gpio_bits_TogglePin(GPIOB,GPIO_PINS_9);
  定时器4PWM输出配置:
void Tmr4PWM_init(uint16_t Period)
{
  /* tmr4 clock enable */
  crm_periph_clock_enable(CRM_TMR4_PERIPH_CLOCK, TRUE);
  /* gpioa gpiob clock enable */
  crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
  
  gpio_init_type gpio_init_struct;
  tmr_output_config_type tmr_oc_init_structure;
  
  gpio_default_para_init(&gpio_init_struct);
  gpio_init_struct.gpio_pins = GPIO_PINS_7 | GPIO_PINS_8 | GPIO_PINS_9;
  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init(GPIOB, &gpio_init_struct);
  
  /* tmr4 configuration */
  /* time base configuration */
  /* systemclock/14400/10000 = 1hz */
  tmr_base_init(TMR4, 1000000/Period - 1, 144 - 1);
  tmr_cnt_dir_set(TMR4, TMR_COUNT_UP);
  tmr_clock_source_div_set(TMR4, TMR_CLOCK_DIV1);
  
  tmr_output_default_para_init(&tmr_oc_init_structure);
  tmr_oc_init_structure.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A;
  tmr_oc_init_structure.oc_idle_state = TRUE;
  tmr_oc_init_structure.oc_polarity = TMR_OUTPUT_ACTIVE_LOW;
  tmr_oc_init_structure.oc_output_state = TRUE;

  tmr_output_channel_config(TMR4, TMR_SELECT_CHANNEL_2, &tmr_oc_init_structure);
  tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_2, 0);
  tmr_output_channel_buffer_enable(TMR4, TMR_SELECT_CHANNEL_2, TRUE);

  tmr_output_channel_config(TMR4, TMR_SELECT_CHANNEL_3, &tmr_oc_init_structure);
  tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_3, 0);
  tmr_output_channel_buffer_enable(TMR4, TMR_SELECT_CHANNEL_3, TRUE);

  tmr_output_channel_config(TMR4, TMR_SELECT_CHANNEL_4, &tmr_oc_init_structure);
  tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_4, 0);
  tmr_output_channel_buffer_enable(TMR4, TMR_SELECT_CHANNEL_4, TRUE);

  tmr_period_buffer_enable(TMR4, TRUE);

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

if(LED.UpFlag == 0)
    {
      if(LED.Mode_Dis == 0 || LED.Mode_Dis == 1)
      {
        LED.Upcnt++;
        if(LED.Upcnt%100 == 0)
        {
          LED.state++;
          LED.state %= 3;
          LED.Upcnt = 0;
          LED.UpFlag = 1;
        }
      }
      else if(LED.Mode_Dis == 2)
      {
//        PWMcnt = Tmr4PWM/10*2;
        LED.Upcnt++;
        if(LED.Upcnt%200 == 0)
        {
          LED.state++;
          LED.state %= 3;
          LED.Upcnt = 0;
          LED.UpFlag = 1;
        }
        if(LED.Upcnt <= 100)
        {
          LED.PWMcnt = LED.Upcnt;
        }
        if(LED.Upcnt <= 200 && LED.Upcnt > 100)
        {
          LED.PWMcnt = 200 - LED.Upcnt;
        }
      }
    }
  LED执行函数:
void App_LED(void)
{
  if(LED.Mode_OidDis != LED.Mode_Dis)
  {
    LED.Upcnt = 0;
    LED.state = 0;
    LED.UpFlag = 1;
   
    if(LED.Mode_OidDis == 2)
    {
      tmr_counter_enable(TMR4, FALSE);
      LED_GPIO_init();
      
    }
    else
    {
      LEDRed_off;
      LEDYellow_off;
      LEDGreen_off;
    }

    switch(LED.Mode_Dis)
    {
      case 0:
        LEDRed_on;
        LEDYellow_on;
        LEDGreen_on;
        break;
        
      case 1:
        LEDRed_on;
        break;
        
      case 2:
        Tmr4PWM_init(Tmr4PWM);
        LED.Upcnt = 0;
        break;

      default:
        break;
    }
    LED.Mode_OidDis = LED.Mode_Dis;
  }
  
  if(LED.UpFlag == 1)
  {
    if(LED.Mode_Dis == 0)
    {
      LEDRed_Toggle;
      LEDYellow_Toggle;
      LEDGreen_Toggle;
    }
    else if(LED.Mode_Dis == 1)
    {
      switch(LED.state)
      {
        case 0:
          LEDRed_on;
          LEDGreen_off;
          break;
         
        case 1:
          LEDRed_Toggle;
          LEDYellow_Toggle;
          break;
         
        case 2:
          LEDYellow_Toggle;
          LEDGreen_Toggle;
          break;
         
        default:
          break;
      }
    }
    else if(LED.Mode_Dis == 2)
    {
      switch(LED.state)
      {
        case 0:
          tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_2, LED.PWMcnt*50);
          break;
         
        case 1:
          tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_3, LED.PWMcnt*50);
          break;
         
        case 2:
          tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_4, LED.PWMcnt*50);
          break;
         
        default:
          break;
      }
    }
    LED.UpFlag = 0;
  }
}
6)AHT20数据获取接AHT界面设计
  其实模拟IIC就是两个引脚的IO状态来模拟时序,通过IO口的高低电平及上升下降沿来完美模拟时序,本开发板对应的IIC接口是PB7和PB6,注意PB7同时是红灯的控制引脚,通过IO口模拟正确读取了数据,不过使用硬件IIC是并没有成功,一直得不到从机的回复,考虑到速度问题,就没有继续进行硬件IIC的实现,也希望大佬可以指导一下雅特力的硬件IIC。
  模拟IIC配置:
#define IIC1_RCU_GPIOB_clock    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE)
#define IIC1_SDA_INITOut        IIC1_SDA_GPIO_OutConfig()
#define IIC1_SDA_INITIn         IIC1_SDA_GPIO_InConfig()
#define IIC1_SDA_SET            gpio_bits_set(GPIOB,GPIO_PINS_7)                  
#define IIC1_SDA_RESET          gpio_bits_reset(GPIOB,GPIO_PINS_7)
#define IIC1_ReadSDA            gpio_input_data_bit_read(GPIOB, GPIO_PINS_7)

#define IIC1_SCL_INITOut        IIC1_SCL_GPIO_OutConfig()
#define IIC1_SCL_SET            gpio_bits_set(GPIOB,GPIO_PINS_6)                  
#define IIC1_SCL_RESET          gpio_bits_reset(GPIOB,GPIO_PINS_6)

void IIC1_IOInit(void)
{
  gpio_init_type gpio_init_struct;
  IIC1_RCU_GPIOB_clock;
  
  gpio_default_para_init(&gpio_init_struct);

  gpio_init_struct.gpio_drive_strength  = GPIO_DRIVE_STRENGTH_MAXIMUM;
  gpio_init_struct.gpio_out_type        = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode            = GPIO_MODE_OUTPUT;
  gpio_init_struct.gpio_pins            = GPIO_PINS_6|GPIO_PINS_7;
  gpio_init_struct.gpio_pull            = GPIO_PULL_UP;
  gpio_init(GPIOB, &gpio_init_struct);
  
  IIC1_SDA_SET;
  IIC1_SCL_SET;

}

void IIC1_SDA_GPIO_OutConfig(void)
{
  gpio_init_type gpio_init_struct;
  IIC1_RCU_GPIOB_clock;

  gpio_default_para_init(&gpio_init_struct);
  gpio_init_struct.gpio_drive_strength  = GPIO_DRIVE_STRENGTH_MAXIMUM;
  gpio_init_struct.gpio_out_type        = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode            = GPIO_MODE_OUTPUT;
  gpio_init_struct.gpio_pins            = GPIO_PINS_7;
  gpio_init_struct.gpio_pull            = GPIO_PULL_UP;
  gpio_init(GPIOB, &gpio_init_struct);
}

void IIC1_SDA_GPIO_InConfig(void)
{
  gpio_init_type gpio_init_struct;
  IIC1_RCU_GPIOB_clock;

  gpio_default_para_init(&gpio_init_struct);
  gpio_init_struct.gpio_mode            = GPIO_MODE_INPUT;
  gpio_init_struct.gpio_pins            = GPIO_PINS_7;
  gpio_init_struct.gpio_pull            = GPIO_PULL_NONE;
  gpio_init(GPIOB, &gpio_init_struct);
}

void IIC1_SCL_GPIO_OutConfig(void)
{
  gpio_init_type gpio_init_struct;
  IIC1_RCU_GPIOB_clock;

  gpio_default_para_init(&gpio_init_struct);
  gpio_init_struct.gpio_drive_strength  = GPIO_DRIVE_STRENGTH_MAXIMUM;
  gpio_init_struct.gpio_out_type        = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode            = GPIO_MODE_OUTPUT;
  gpio_init_struct.gpio_pins            = GPIO_PINS_6;
  gpio_init_struct.gpio_pull            = GPIO_PULL_UP;
  gpio_init(GPIOB, &gpio_init_struct);
}

void IIC1_IIC_Init(void)
{
  IIC1_SDA_INITOut;
//  IIC1_IIC_Stop();
  IIC1_SDA_RESET;
  IIC1_SCL_RESET;
}

void IIC1_IIC_Start(void)
{
  IIC1_SDA_SET;
  delay_us(8);
  IIC1_SCL_SET;
  delay_us(14);
  IIC1_SDA_RESET;
  delay_us(14);
  IIC1_SCL_RESET;
  delay_us(14);
}

void IIC1_IIC_Stop(void)
{
  IIC1_SDA_RESET;
  delay_us(14);
  IIC1_SCL_SET;
  delay_us(8);
  IIC1_SDA_SET;
  delay_us(14);
}
void IIC1_SendACK(uint8_t ack)  
{
  IIC1_SDA_INITOut;
  if(ack == 0)
  IIC1_SDA_RESET;                                                              //写应答信号
  else
  IIC1_SDA_SET;  
  delay_us(14);
  IIC1_SCL_SET;                                                                //拉高时钟线  
  delay_us(14);                                                           //延时  
  IIC1_SCL_RESET;                                                              //拉低时钟线  
  delay_us(14);                                                           //延时   
}

uint8_t IIC1_RecvACK(void)  
{  
  
  uint8_t RecvACK;
   
  IIC1_SDA_INITIn;                                                    //SDA接口为输入
  delay_us(8);
  IIC1_SCL_SET;                                                                //拉高时钟线  
  delay_us(8);                                                           //延时  
  RecvACK = IIC1_ReadSDA;                                                      //读应答信号  
  IIC1_SCL_RESET;                                                              //拉低时钟线  
  delay_us(8);                                                           //延时
  IIC1_SDA_INITOut;
   
  return RecvACK;
   
}

uint8_t IIC1_SendByte(uint8_t dat)  
{  
  uint8_t datsendbit;
  uint8_t RecvACK;
   
  for (uint8_t i=0; i<8; i++)                                                   //8位计数器  
  {  
    datsendbit = ((dat & 0x80) >> 7);
    dat <<= 1;                                                                  //移出数据的最高位
    if(datsendbit == 1)
    {
      IIC1_SDA_SET;
    }
    if(datsendbit == 0)
    {
      IIC1_SDA_RESET;
    }                                                                           //送数据口
    delay_us(8);
    IIC1_SCL_SET;                                                               //拉高时钟线  
    delay_us(8);                                                                //延时  
    IIC1_SCL_RESET;                                                             //拉低时钟线
    delay_us(8);  
  }
  RecvACK = IIC1_RecvACK();
  return RecvACK;  
}

uint8_t IIC1_RecvByte(void)  
{   
  uint8_t RecvDat = 0;
  
  IIC1_SDA_INITIn;
  for (uint8_t i=0; i<8; i++)                                                   //8位计数器  
  {  
    RecvDat <<= 1;
    IIC1_SCL_SET;                                                               //拉高时钟线  
    delay_us(10);                                                               //延时
    RecvDat |= (IIC1_ReadSDA);
    IIC1_SCL_RESET;                                                             //拉低时钟线  
    delay_us(10);                                                               //延时   
  }
  IIC1_SDA_INITOut;
  return RecvDat;
      
}

void IIC1_SendBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr)  
{  
  uint8_t ack = 0;
  IIC1_IIC_Start();
  IIC1_SendByte(dev_addr<<1);
  
  for(uint8_t i = 0; i < len; i++)
  {
    ack = IIC1_SendByte(*(dat+i));
  }
  IIC1_IIC_Stop();
}

void IIC1_RecvBytes(uint8_t len,uint8_t* dat,uint8_t dev_addr)
{  
  IIC1_IIC_Start();
  IIC1_SendByte((dev_addr<<1)+1);
  
  for(uint8_t i = 0; i < len; i++)
  {
    *(dat+i) = IIC1_RecvByte();
   
    if(i == (len - 1))
    {
      IIC1_SendACK(1);
    }
    else
    {
      IIC1_SendACK(0);
    }
  }
  IIC1_IIC_Stop();
}
  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初始化:
void ertc_config(void)
{
  /* allow access to ertc */
  pwc_battery_powered_domain_access(TRUE);
  /* reset ertc domain */
  crm_battery_powered_domain_reset(TRUE);
  crm_battery_powered_domain_reset(FALSE);
  /* enable the lext osc */
  crm_clock_source_enable(CRM_CLOCK_SOURCE_LEXT, TRUE);
  /* wait till lext is ready */
  while(crm_flag_get(CRM_LEXT_STABLE_FLAG) == RESET)
  {
  }
  /* select the ertc clock source */
  crm_ertc_clock_select(CRM_ERTC_CLOCK_LEXT);
  /* enable the ertc clock */
  crm_ertc_clock_enable(TRUE);

  /* deinitializes the ertc registers */
  ertc_reset();
  /* wait for ertc apb registers update */
  ertc_wait_update();
  
  /* configure the ertc divider */
  /* ertc second(1hz) = ertc_clk / (div_a + 1) * (div_b + 1) */
  ertc_divider_set(127, 255);
  /* configure the ertc hour mode */
  ertc_hour_mode_set(ERTC_HOUR_MODE_24);

  eRTC_set.year     = 22;
  eRTC_set.month    = 8;
  eRTC_set.day      = 18;
  eRTC_set.hour     = 8;
  eRTC_set.min      = 0;
  eRTC_set.sec      = 0;
  eRTC_set.week     = 4;
  Set_Time(&eRTC_set);
}
  应用函数:
void Set_Time(ertc_time_type* time)
{
  /* set date  */
  ertc_date_set(time->year,time->month,time->day,time->week);
  /* set time*/
  ertc_time_set(time->hour,time->min,time->sec,ERTC_AM);
}

uint32_t bpr_reg_get(uint8_t index)
{
  if(index >= ERTC_BPR_DT_NUMBER)
  {
    index = 0;
  }
  return ertc_bpr_data_read(bpr_addr_tab[index]);
}

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

  /* configure the usart2 tx pin */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  gpio_init_struct.gpio_pins = GPIO_PINS_2;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init(GPIOA, &gpio_init_struct);
  
  /* configure the usart2 rx pin */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  gpio_init_struct.gpio_pins = GPIO_PINS_3;
  gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  gpio_init(GPIOA, &gpio_init_struct);
  
  /* config usart nvic interrupt */
  nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  nvic_irq_enable(USART2_IRQn, 0, 0);
  
  /* configure usart2 param */
  usart_init(USART2, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);
  usart_transmitter_enable(USART2, TRUE);
  usart_receiver_enable(USART2, TRUE);
  
  /* enable usart2 interrupt */
  usart_interrupt_enable(USART2, USART_RDBF_INT, TRUE);
  usart_enable(USART2, TRUE);

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

//******************************************************************************
//* 函数名称  : USART_sendbit(TxBuffer)
//* 函数描述  : 串口发送多个字节
//* 输入参数  :
//* 参数描述  :  TxBuffer:存储发送的一个字节
//* 输出参数  : 无
//* 返回值    : 无
//******************************************************************************   
void USART2_sendbits(uint8_t *HzpAscii)
{
  while(*HzpAscii != 0)
  {
    usart_data_transmit(USART2,*HzpAscii);
    while((usart_flag_get(USART2, USART_TDBE_FLAG) == RESET));
    HzpAscii += 1;
  }
  
}
//******************************************************************************
// 函数名称  : USART2_deal
// 函数描述  : 串口中断处理
// 输入参数  :
// 参数描述  : 无
// 输出参数  : 无
// 返回值    : 无
//******************************************************************************
void USART2_deal(uint8_t USART_data)
{
  
  uint8_t check = 0;
  
  if(USART_data == 0xA5 && Com_Data.ing_step == 0)
  {
    Com_Data.STX_1 = 0xA5;
    Com_Data.ing_step = 1;
  }
  else if(USART_data == 0x5A && Com_Data.ing_step == 1)
  {
    Com_Data.STX_2 = 0x5A;
    Com_Data.ing_step = 2;
  }
  else if(Com_Data.ing_step == 2)
  {
    Com_Data.Length = USART_data;
    Com_Data.ing_step = 3;
  }
  else if(Com_Data.ing_step == 3)
  {
    RecePackBuf[Com_Data.ReturnCnt] = USART_data;
    Com_Data.ReturnCnt ++;
    if(Com_Data.Length == Com_Data.ReturnCnt)
    {
      Com_Data.CHECKSUM_1 = RecePackBuf[Com_Data.ReturnCnt-1];
      for(uint8_t i=0;i<Com_Data.Length-1;i++)
      {
        check += RecePackBuf[i];
      }
      if(Com_Data.CHECKSUM_1 = check)//校验成功
      {
        line_** = 2;
        Com_Data.CMD = RecePackBuf[0];
      }
      else
      {
        memset(RecePackBuf, 0,ARRAYNUM(RecePackBuf));//清空接收包
        memset(&Com_Data,0,sizeof(Com_Data));//清空结构体
      }
    }
  }
  else
  {
    memset(RecePackBuf, 0,ARRAYNUM(RecePackBuf));//清空接收包
    memset(&Com_Data,0,sizeof(Com_Data));//清空结构体
  }
}
  对于接收具体处理,这边采用的是通信协议的方式进行甄别,实现方式千千万,只取适合自己的那一瓢,这时候就可以把设置时间放到了这里,同时也可以控制LED的显示,只要正确解析就可以。
9)蓝牙通信
  其实所谓蓝牙通信实现的功能就是串口通信的无线化,其透传模式功能实现的就是串口通信的延伸,命令模式就是对蓝牙模块的配置。本开发板通过串口3和蓝牙模块的耦合实现芯片自带的蓝牙功能。最开始测试想把开发板作为主机进行扫描的,不过通过对资料的分析,这个工程有点大,本次测试提供的资料里只有简单的AT指令,所以改变目标,实现基本透传功能。
  串口3使用的是空闲中断+DMA的方式进行的,这样可以减少串口中断的次数,蓝牙切换为透传模式也是非常方便的,发送"AT+TPMODE1\r\n"就可以。
  串口三初始化:
void USART3_init(void)
{
  gpio_init_type gpio_init_struct;
  
  crm_periph_clock_enable(CRM_USART3_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);  
  crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
  
  gpio_pin_remap_config(USART3_GMUX_0010, TRUE);
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  gpio_init_struct.gpio_pins = GPIO_PINS_7;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init(GPIOA, &gpio_init_struct);
  
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  gpio_init_struct.gpio_pins = GPIO_PINS_6;
  gpio_init_struct.gpio_pull = GPIO_PULL_UP;
  gpio_init(GPIOA, &gpio_init_struct);
  
  usart_init(USART3, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);
  usart_transmitter_enable(USART3, TRUE);
  usart_receiver_enable(USART3, TRUE);
  usart_dma_receiver_enable(USART3, TRUE);
  
  USART3_DMA1_config();

  nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  nvic_irq_enable(USART3_IRQn, 0, 0);
  /* Enable the USARTx Interrupt */
  usart_interrupt_enable(USART3, USART_IDLE_INT, TRUE);
//  usart_interrupt_enable(USART3, USART_RDBF_INT, TRUE);
  usart_enable(USART3, TRUE);
  
}
DMA初始化:
void USART3_DMA1_config(void)
{
  dma_init_type dma_init_struct;

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

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

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

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

  ReturnCnt = ARRAYNUM(USART3RecePackBuf)-dma_data_number_get(DMA1_CHANNEL3);
  memcpy(BLEPackBuf,USART3RecePackBuf,ReturnCnt);
  memset(USART3RecePackBuf, 0,ReturnCnt);//清空接收包
  
//  usart_data_transmit(USART0, RecePackBuf[0]);
//  while((usart_flag_get(USART0, USART_FLAG_TBE) == RESET));
  if(BLEPackBuf[0] == 0xA5 && BLEPackBuf[1] == 0x5A)
  {
    Com_Data.Length     = BLEPackBuf[2];
    Com_Data.CHECKSUM_1 = BLEPackBuf[ReturnCnt-1];
   
    for(uint8_t i=0;i<Com_Data.Length-1;i++)
    {
      check += BLEPackBuf[i+3];
    }
    if(Com_Data.CHECKSUM_1 = check)//校验成功
    {
      line_** = 3;
      memcpy(RecePackBuf,BLEPackBuf+3,ReturnCnt-4);
      Com_Data.CMD = RecePackBuf[0];
      memset(BLEPackBuf, 0,Com_Data.Length+3);//清空接收包
    }
    else
    {
      memset(BLEPackBuf, 0,ARRAYNUM(BLEPackBuf));//清空接收包
      memset(&Com_Data,0,sizeof(Com_Data));//清空结构体
    }
   
   
  }

  USART3_DMA1_config();
}
这里一共用到了三个数组,实现对接收数据的隔离及缓存,我们在进入空闲中断是需要关闭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






使用特权

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

使用特权

评论回复
评论
qintian0303 2022-9-15 17:09 回复TA
年份是一个8位数,也就是或最多可以设置2000到2255年?我的理解对吗,如果是这样的话我就能理解了 
地板
xu@xupt| | 2022-12-11 00:20 | 只看该作者
很详细的教程,感谢分享

使用特权

评论回复
发新帖 本帖赏金 20.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

305

主题

1752

帖子

8

粉丝