AT32固件库外设使用,ArduinoAPI接口移植,模块化

news2024/12/23 10:42:49

目录

  • 一、ArduinoAPI移植
  • 一、通用定时器使用
    • 1.计时
    • 1.
    • 2.ETR外部时钟计数
    • 4.ArduinoAPI - timer
  • 三、ADC
    • 1.ADC初始化(非DMA)
    • 2.ADC_DMA 规则通道扫描
  • 六、USB HID IAP
    • 1.准备好Bootloader和app
    • 2.配置好时钟,一定要打开USB
    • 3.将生成的时钟配置复制到bootloader和app对应位置
    • 4 设置bootloader和app的起始位置
    • 5 使用IAP Programmer下载,地址要设置为app地址

一、ArduinoAPI移植

通过arduinoapi实现封装,实现底层分离,支持arduino生态,
通过固件库模块化外设,由ArduinoAPI调用
参考FastShift的封装方式,由于F403A固件库升级,底层需要重新封装

一、通用定时器使用

1.计时

在这里插入图片描述

在这里插入图片描述
由图可以看出AHB时钟为240M
定时器时钟为240M

时间计算
Tout= ((arr+1)(psc+1))/Tclk;
Tclk:TIM3的输入时钟频率(单位为MHz)。
Tout:TIM3溢出时间(单位为us)。
例:计时1ms,输入时钟频率为240MHz。
  arr = 239,psc = 999。
  Tout = ((arr+1)
(psc+1))/Tclk = ((239+1) *(240+1))/240=1000(us)=1(ms)

void trm3_int_init(u16 arr, u16 psc)
{

/* enable tmr1 clock */
  crm_periph_clock_enable(CRM_TMR3_PERIPH_CLOCK, TRUE);

  tmr_base_init(TMR3, arr, psc);
  tmr_cnt_dir_set(TMR3, TMR_COUNT_UP);
  tmr_interrupt_enable(TMR3, TMR_OVF_INT, TRUE);

  /* tmr1 overflow interrupt nvic init */
  nvic_priority_group_config(NVIC_PRIORITY_GROUP_0);
  nvic_irq_enable(TMR3_GLOBAL_IRQn, 1, 0);

  /* enable tmr3 */
  tmr_counter_enable(TMR3, TRUE);  
}
 
void TMR3_GLOBAL_IRQHandler(void)
{ 		  
  TMR3->ists = 0;;
  lv_tick_inc(1);	     
}

1.

2.ETR外部时钟计数

对于外部脉冲(方波)计数,通用的方法为捕获比较方式,由于项目对于脉冲的精度要求比较高,在快速搭建代码测试过后,发现该方法并不能满足需求,进而寻求计数更为精确的方法----ETR计数。

定时器实际就是一个计数器
可选内部、外部、内部触发输入用作计数时钟
即使用外部触发ETR作为计数器触发源

参考https://blog.csdn.net/u010650845/article/details/81781670

4.ArduinoAPI - timer


void Timer_SetInterrupt(TIM_TypeDef* TIMx, uint32_t Time, Timer_CallbackFunction_t Function)
{
    uint16_t period = 0;
    uint16_t prescaler = 0;
    uint32_t clock = TIMER_GET_CLOCK_MAX(TIMx);

    if(!IS_TMR_ALL_PERIPH(TIMx) || Time == 0)
    {
        return;
    }

    /*将定时中断时间转换为重装值和时钟分频值*/
    Timer_TimeFactorization(
        Time,
        clock,
        &period,
        &prescaler
    );

    /*定时中断配置*/
    Timer_SetInterruptBase(
        TIMx,
        period,
        prescaler,
        Function,
        TIMER_PREEMPTIONPRIORITY_DEFAULT,
        TIMER_SUBPRIORITY_DEFAULT
    );
}

三、ADC

1.ADC初始化(非DMA)


/**
  * @brief  ADC 配置
  * @param  ADCx: ADC地址
  * @retval 无
  */
void ADCx_Init(adc_type* ADCx)
{
    adc_base_config_type adc_base_struct;
    
    if(ADCx == ADC1)
    {
        crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
    }
    else if(ADCx == ADC2)
    {
        crm_periph_clock_enable(CRM_ADC2_PERIPH_CLOCK, TRUE);
    }
    else if(ADCx == ADC3)
    {
        crm_periph_clock_enable(CRM_ADC3_PERIPH_CLOCK, TRUE);
    }
    else
    {
        return;
    }

	/* select combine mode */
	adc_combine_mode_select(ADC_INDEPENDENT_MODE);
	adc_base_default_para_init(&adc_base_struct);
	adc_base_struct.sequence_mode = FALSE;
	adc_base_struct.repeat_mode = FALSE;
	adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
	adc_base_struct.ordinary_channel_length = 1;
	adc_base_config(ADCx, &adc_base_struct);
	adc_resolution_set(ADCx, ADC_RESOLUTION_12B);
	
	adc_ordinary_conversion_trigger_set(ADCx, ADC_ORDINARY_TRIG_TMR1CH1, ADC_ORDINARY_TRIG_EDGE_NONE);
	
	adc_dma_mode_enable(ADCx, FALSE);
	adc_dma_request_repeat_enable(ADCx, FALSE);
	adc_interrupt_enable(ADCx, ADC_OCCO_INT, FALSE);
	
	adc_enable(ADCx, TRUE);
	while(adc_flag_get(ADCx, ADC_RDY_FLAG) == RESET);
	
	/* adc calibration */
	adc_calibration_init(ADCx);
	while(adc_calibration_init_status_get(ADCx));
	adc_calibration_start(ADCx);
	while(adc_calibration_status_get(ADCx));

}

/**
  * @brief  获取 ADC 值
  * @param  ADCx: ADC地址
  * @param  ADC_Channel: ADC通道
  * @retval 无
  */
uint16_t ADCx_GetValue(adc_type* ADCx, uint16_t ADC_Channel)
{
#if 0
    adc_ordinary_channel_set(ADCx, (adc_channel_select_type)ADC_Channel, 1, ADC_SAMPLETIME_47_5);

    adc_ordinary_software_trigger_enable(ADCx, TRUE);
    while(!adc_flag_get(ADCx, ADC_OCCE_FLAG));
#endif
    return adc_ordinary_conversion_data_get(ADCx);

}

2.ADC_DMA 规则通道扫描

通道注册API

	pinMode(PWR_FWD_L_Pin, INPUT_ANALOG_DMA);
	pinMode(PWR_FWD_M_Pin, INPUT_ANALOG_DMA);
	pinMode(PWR_RET_L_Pin, INPUT_ANALOG_DMA);
	pinMode(PWR_RET_M_Pin, INPUT_ANALOG_DMA);

pinMode会调用ADC_DMA_Register

/**
  * @brief  注册需要DMA搬运的ADC通道
  * @param  ADC_Channel:ADC通道号
  * @retval 见ADC_DMA_Res_Type
  */
ADC_DMA_Res_Type ADC_DMA_Register(uint8_t ADC_Channel)
{
#if 1
    /*初始化ADC通道列表*/
    static bool isInit = false;
    if(!isInit)
    {
        uint8_t i;
        for(i = 0; i < ADC_DMA_REGMAX; i++)
        {
            ADC_DMA_RegChannelList[i] = 0xFF;
        }
        isInit = true;
    }

    /*是否是合法ADC通道*/
    if(!IS_ADC_CHANNEL(ADC_Channel))
        return ADC_DMA_RES_NOT_ADC_CHANNEL;

    /*是否已在引脚列表重复注册*/
    if(ADC_DMA_SearchChannel(ADC_Channel) != -1)
        return ADC_DMA_RES_DUPLICATE_REGISTRATION;

    /*是否超出最大注册个数*/
    if(ADC_DMA_RegCnt >= ADC_DMA_REGMAX)
        return ADC_DMA_RES_MAX_NUM_OF_REGISTRATIONS_EXCEEDED;

    /*写入注册列表*/
    ADC_DMA_RegChannelList[ADC_DMA_RegCnt] = ADC_Channel;

    /*注册个数+1*/
    ADC_DMA_RegCnt++;
#endif
    return ADC_DMA_RES_OK;
}

ADC_DMA_Init函数必须放到所有ADC_DMA引脚注册完之后

/**
* @brief  ADC DMA 配置  配置ADC和对应DMA,固定ADC1 如果不需要DMA则使用ADCx_Init函数
  *       需要放到初始化最后,或者所有ADC_DMA引脚注册完之后
  * @param  无
  * @retval 无
  */
void ADC_DMA_Init(void)
{

    uint8_t index;
    dma_init_type dma_init_structure;
    adc_base_config_type adc_base_struct;

    /*CLOCK CONFIG*/
    crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
    
	/*INTERUPT COFIG*/
	nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0);

    /*DMA CONFIG*/
    dma_reset(DMA1_CHANNEL1);

    dma_default_para_init(&dma_init_structure);
    dma_init_structure.buffer_size = ADC_DMA_RegCnt;
    dma_init_structure.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
    dma_init_structure.memory_base_addr = (uint32_t)ADC_DMA_ConvertedValue;
    dma_init_structure.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
    dma_init_structure.memory_inc_enable = TRUE;
    dma_init_structure.peripheral_base_addr = (uint32_t) (&(ADC1->odt));
    dma_init_structure.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
    dma_init_structure.peripheral_inc_enable = FALSE;
    dma_init_structure.priority = DMA_PRIORITY_HIGH;
    dma_init_structure.loop_mode_enable = TRUE;

    dma_init(DMA1_CHANNEL1, &dma_init_structure);
	
	dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
	
    dma_channel_enable(DMA1_CHANNEL1, TRUE);


    /*ADC CONFIG*/
	adc_combine_mode_select(ADC_INDEPENDENT_MODE);
    adc_base_default_para_init(&adc_base_struct);

    adc_base_struct.sequence_mode = TRUE;
    adc_base_struct.repeat_mode = TRUE;
    adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
    adc_base_struct.ordinary_channel_length = ADC_DMA_RegCnt;
    adc_base_config(ADC1, &adc_base_struct);


    for(index = 0; index < ADC_DMA_RegCnt; index++)
    {
        adc_ordinary_channel_set(
            ADC1,
            (adc_channel_select_type)ADC_DMA_RegChannelList[index],
            index + 1,
            ADC_SAMPLETIME_41_5
        );
    }

  
    adc_ordinary_conversion_trigger_set(ADC1, ADC12_ORDINARY_TRIG_SOFTWARE, TRUE);
    adc_dma_mode_enable(ADC1, TRUE);
  
 
    adc_enable(ADC1, TRUE);
    adc_calibration_init(ADC1);
    while(adc_calibration_init_status_get(ADC1));
    adc_calibration_start(ADC1);
    while(adc_calibration_status_get(ADC1));

}

两种方式 :1 DMA完成中断中再次软件触发,实现循环采样,中断频率较高
2 ADC_DMA_GetValue中软件触发,需要获取数据时才开启采集
通过CONFIG_ADC_CIRCLE_ENABLE 进行切换

void DMA1_Channel1_IRQHandler(void)
{
  if(dma_flag_get(DMA1_FDT1_FLAG) != RESET)
  {
    dma_flag_clear(DMA1_FDT1_FLAG);
   
	  
#if (CONFIG_ADC_CIRCLE_ENABLE == 1)
	adc_ordinary_software_trigger_enable(ADC1, TRUE);
#else
	   dma_trans_complete_flag = 1;
#endif
  }
}

/**
  * @brief  获取DMA搬运的ADC值
  * @param  ADC_Channel:ADC通道号
  * @retval ADC值
  */
uint16_t ADC_DMA_GetValue(uint8_t ADC_Channel)
{
    int16_t index;

    if(!IS_ADC_CHANNEL(ADC_Channel))
        return 0;

    index = ADC_DMA_SearchChannel(ADC_Channel);
    if(index == -1)
        return 0;

#if (CONFIG_ADC_CIRCLE_ENABLE == 0) 
	adc_ordinary_software_trigger_enable(ADC1, TRUE);
	while(dma_trans_complete_flag == 0);
	dma_trans_complete_flag = 0;
#endif
	
    return ADC_DMA_ConvertedValue[index];
}

六、USB HID IAP

1.准备好Bootloader和app

在这里插入图片描述

2.配置好时钟,一定要打开USB

在这里插入图片描述

3.将生成的时钟配置复制到bootloader和app对应位置

设置正确才能正确识别HID设备,并且免驱,否则无法识别usb

void system_clock_config(void)
{
   /* reset crm */
  crm_reset();

  /* enable hext */
  crm_clock_source_enable(CRM_CLOCK_SOURCE_HEXT, TRUE);

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


  /* config pll clock resource */
  crm_pll_config(CRM_PLL_SOURCE_HEXT, CRM_PLL_MULT_15, CRM_PLL_OUTPUT_RANGE_GT72MHZ);

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

  /* wait till pll is ready */
  while(crm_flag_get(CRM_PLL_STABLE_FLAG) != SET)
  {
  }


  /* config ahbclk */
  crm_ahb_div_set(CRM_AHB_DIV_1);

  /* config apb2clk */
  crm_apb2_div_set(CRM_APB2_DIV_2);

  /* config apb1clk */
  crm_apb1_div_set(CRM_APB1_DIV_2);

  /* enable auto step mode */
  crm_auto_step_mode_enable(TRUE);


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

  /* wait till pll is used as system clock source */
  while(crm_sysclk_switch_status_get() != CRM_SCLK_PLL)
  {
  }


  /* disable auto step mode */
  crm_auto_step_mode_enable(FALSE);


  /* update system_core_clock global variable */
  system_core_clock_update();
}

4 设置bootloader和app的起始位置

bootloader
在这里插入图片描述

app
在这里插入图片描述
在这里插入图片描述
保持一致

5 使用IAP Programmer下载,地址要设置为app地址

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1135991.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

每日汇评:黄金形态确认牛市,再次尝试上行2000美元

金价挑战1988美元的关键阻力位&#xff0c;向2000美元进发&#xff1b; 在避险情绪中&#xff0c;美元随着美债收益率扩大复苏&#xff1b; 黄金价格在日线图上确认了一个多头标志&#xff0c;RSI指数仍然指向更多的上涨&#xff1b; 随着中东紧张局势再次引起人们的关注&#…

前列腺特异抗原(PSA)介绍

前列腺特异抗原(Prostate Specific Antigen&#xff0c;PSA)是由前列腺腺泡和导管的上皮细胞分泌的一种单链糖蛋白&#xff0c;在功能上属于类激肽释放酶的一种丝氨酸蛋白酶&#xff0c;参与精液的液化过程&#xff0c;是常规用于前列腺良性与恶性疾病诊断与鉴别诊断的重要指标…

LuaTable转C#的列表List和字典Dictionary

LuaTable转C#的列表List和字典Dictionaty 介绍lua中创建表测试lua中list表表转成List表转成Dictionary 键值对表表转成Dictionary 多类型键值对表表转成Dictionary 总结 介绍 之前基本都是从C#中的List或者Dictionary转成luaTable&#xff0c;很少会把LuaTable转成C#的List或者…

openEuler 22.03 LTS编译安装libreoffice并制作rpm包——筑梦之路

环境说明 操作系统&#xff1a;华为欧拉操作系统openEuler 22.03 lts x86_64 libreoffice版本&#xff1a;当前最新版本7.6 编译安装过程 1. 安装编译工具和依赖包 sudo yum install -y snappy snappy-devel autoconf automake libtool git gcc gcc-c gcc-objc make cmake…

超全整理,服务端性能测试-docker部署tomcat/redis(详细步骤)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、docker部署tom…

全电注塑机硬件选型

电机选型&#xff08;方法&#xff09; 在伺服电机选型计算当中其主要数据包括&#xff1a;负载/ 电机惯量比&#xff0c;加减速力矩&#xff0c; 负载转矩&#xff0c;连续过载时间等。选择原则是&#xff1a;首先根据转矩&#xff0d;速度特性曲线检查负载转矩&#xff0c;加…

解决photoshop中不能输入蒙文的方法(附所有软件、字体)

效果预览&#xff1a; ps版本&#xff1a;Adobe Photoshop 2020 windows版本&#xff1a;windows 11专业版 蒙文字体选用&#xff1a;Menk Garqag Tig 蒙文输入法&#xff1a;蒙科立智能输入发下载地址&#xff1a;蒙科立-蒙古文AI&#xff08;人工智能&#xff09;引领者 …

跨境电商测评方式有哪些?

对于做跨境电商平台的卖家来说&#xff0c;如果想要提高销量&#xff0c;测评是一个必不可少的环节&#xff0c;因为前期自然流量很难带来什么销售额&#xff0c;所以很多卖家选择进行测评来提升产品的排名、权重和销量&#xff0c;并增加订单量、点赞、店铺评价和产品评价等指…

Studio One6.5版本要不要更新?哪些人需要更新?更新了哪些内容

对于声卡调试Studio One6.5版本&#xff0c;是否需要更新&#xff1f;这是一个需要考虑的问题。各位好&#xff0c;我是coco玛奇朵。 关于Studio One6.5版本要不要更新&#xff1f;哪些人需要更新&#xff1f;更新了哪些内容&#xff1f;对于这些问题&#xff0c;今天我们来详…

Redis快速上手篇(二)(操作与数据类型)

Key 默认 16 个数据库&#xff0c;类似数组下标从 0 开始&#xff0c;初始默认使用 0 号库 config get databases 查询数据库总数量 dbsize 查看当前数据库的 key 的数量 flushdb 清空当前库 flushall 通杀全部库 keys * 获取当前库中的所有key select 0 选择第一个库 move ke…

VS2022 C# 读取 excel 2023年

今天是2023年6月26日&#xff0c;我有一个excel表要读数据&#xff0c;然后放到winform程序来处理&#xff0c;网上的资料太旧&#xff0c;很多用不起来&#xff0c;试了一个可以使用&#xff0c;记录一下&#xff1a; 一、excel文件后缀需要小写。 二、用VS2022建一个winform…

关于腾讯云轻量应用服务器性能测评,看这一篇文章就够了

腾讯云轻量应用服务器性能如何&#xff1f;为什么便宜是不是性能不行&#xff1f;腾讯云百科txybk.com从轻量应用服务器的CPU型号、处理器主频、内存、公网带宽、月流量和系统盘多方面来详细测评轻量性能&#xff0c;轻量应用服务器性价比高&#xff0c;并不是性能不行&#xf…

rk3588 SD 卡镜像扩容

先用一个卡复制镜像 Win32DiskImager 操作: https://blog.csdn.net/FL1623863129/article/details/118945754 复制之后镜像正常工作 但是仍旧只能显示32G 扩容 下载安装gparted https://blog.csdn.net/weixin_44589540/article/details/121580883 resize 拖过来就完了…

如何实现Android视音频数据对接到GB28181平台(SmartGBD)

为什么要开发Android平台GB28181&#xff1f; 在做Android平台GB28181接入模块之前&#xff0c;我们在RTMP推送播放、RTSP轻量级服务、转发、播放这块&#xff0c;已经有很多年的经验&#xff0c;这意味着&#xff0c;我们不需要重复造轮子&#xff0c;已有屏幕、摄像头或编码…

Keil uVision 5 MDK版软件安装包下载及安装教程(最详细图文教程)

目录 一.简介 二.安装步骤 软件&#xff1a;Keil uvision5版本&#xff1a;MDKv518语言&#xff1a;中文/英文大小&#xff1a;377.01M安装环境&#xff1a;Win11/Win10/Win8/Win7硬件要求&#xff1a;CPU2.59GHz 内存4G(或更高&#xff09;下载通道①百度网盘丨64位下载链接…

【Linux】第三站:Linux基本指令(二)

文章目录 一、通配符 *二、man指令三、cp指令1.先给一个文件里面写入数据2. cp指令拷贝普通文件3.cp指令拷贝文件目录4.常用的选项总结 四、mv指令1.mv命令简介2.使用 五、一些插曲1.一些注意事项2.指令的本质3.再谈输出重定向4.追加重定向5.输入重定向 六、cat指令七、more指令…

liunx Centos-7.5上 rabbitmq安装

在安装rabbitmq中需要注意&#xff1a; 1、rabbitmq依赖于erlang&#xff0c;需要先安装erlang 2、erlang和rabbitmq版本有对应关系 可参考网页&#xff1a;https://www.rabbitmq.com/which-erlang.html 第一步&#xff0c;安装编译工具及库文件,如果服务器上已经有了&…

大事务导致数据库恢复时间长

背景 客户的一套系统从凌晨开始出现运行缓慢&#xff0c;重启SQL Server服务后一个主要的数据库一直处在正在恢复的状态&#xff0c;多次重启SQL Server服务和服务器无果后请我们协助处理。 现象 在SSMS中看到数据库是正在恢复的状态&#xff0c;而且不能被访问。 分析 启动SQ…

全球医疗产品畅销:跨境电商的生命科技

随着数字化时代的到来&#xff0c;跨境电商不仅仅是商业领域的一种革命性力量&#xff0c;更是生命科技行业的重要推动者。这一融合带来了全球医疗产品畅销的新时代&#xff0c;为世界各地的消费者带来了前所未有的便利和机会。本文将深入探讨这一跨境电商的生命科技领域&#…

C# 高级 <一>

一、 特性&#xff08;Attribute&#xff09; .NET 框架提供了三种预定义特性&#xff1a; AttributeUsageConditionalObsolete a. AttributeUsage 它描述了如何使用一个自定义特性类。它规定了特性可应用项目的类型。语法如下&#xff1a; [AttributeUsage(validon,AllowM…