tag 标签: stm32

相关帖子
相关博文
  • 热度 6
    2020-9-24 12:06
    921 次阅读|
    1 个评论
    STM32 串口 DMA方式接收数据及数据处理方法
    通常我们都使用中断方式接收串口数据。用DMA方式接收,效率会更高。 先在CUBE中设置一下。 使用 UART DMA 接收功能,并使用 Circular 模式。收到的数据将循环放在缓冲区里。 #define BUFFERSIZE 128 uint8_t Uart1RxBuf ; // 软件中定义一个接收缓冲区 uint16_t curchr,lastchr; // 指向当前未处理过的字符和最后一个字符。 HAL_UART_Receive_DMA(&huart1,Uart1RxBuf,BUFFERSIZE); // 程序初始化时,需要启动一次 UART DMA 接收。 /* 需要定时查询是否收到数据。 */ NDTR; // NDTR 指示存储空间的剩余长度 if(curchr != lastchr) { LEDRUNON(); // 指示收到一个数据包 SerialParse(Uart1RxBuf,&curchr,lastchr); } 找 SerialParse 寻找自定协议中的数据包的头和尾。 因为数据是循环接收的,有可能一个数据包会分布在缓冲区尾部和头部。索引时,需要取模运算。 (data == 'E')&&(data == 'R')&&(data == 'R') 好处就是,串口一直接收着,不会丢掉任何数据,只要合理的缓冲区长度,并及时处理数据。能达到很高的速度且不丢包。
  • 热度 5
    2020-8-29 08:30
    869 次阅读|
    1 个评论
    使用 timer 产生脉冲波形,控制步进电机转动。当使用微步方式时,脉冲频率等于整步频率乘以细分数。有时,我们需要每步进行处理,也就是在发出脉冲时,产生中断。对于常用的双极步进电机,最快的速度大概是 2000PPS ,也就是一秒钟 10 圈。如果使用 256 细分,则输出脉冲频率为 512K ,这么高频率的中断,显然有问题。 有个方法,可以降低中断数量。 可以使用两个 TIMER ,其中一个用于产生电机控制脉冲。常规的办法是使用 50% 点空比的 PWM 脉冲。 使用两个 TIMER ,其中一个设置为 PWM 输出,另外不个设置为 PWM 无输出 void MOT_StartPPS(uint16_t para){ uint16_t temp; PSC = 99; temp = 0xFFFF ; ARR = temp - 1; CCR2 = temp / 2; PSC = 256*100-1; temp = 0xFFFF; ARR = temp - 1; CCR1 = temp / 2; 。。。。。。 HAL_TIM_PWM_Start(&htim15,TIM_CHANNEL_2); HAL_TIM_PWM_Start_IT(&htim16,TIM_CHANNEL_1); } 对于较高的速度,需要斜坡启动,所以将 PWM 脉冲重复频率设置为最慢,启动 PWM 输出,同时启动另一个 TIMER 的中断输出(这里我们只要中断,不要输出)。 随后在程序中,定时运行步述代码,逐步将频率提高,直到达到设定值。 if(ppsstart == 1){ if((mscnt % SLOPINT)==0){ ppsratenow += SLOPINCPPS; if(ppsratenow < ppsrate){ temprate = ppsratenow; } else{ temprate = ppsrate; ppsstart = 0; ppsratenow = 0; } PSC = 50/temprate; temp = (48000000 / 256) / temprate / (50/temprate + 1) ; ARR = temp - 1; //48000000 / 51200 * para / (para / 100 +1); //para 秒 / 圈 频率 = SYSCLK / ( 256 * para) CCR2 = temp / 2; PSC = 256*(50/temprate + 1)-1; temp = (48000000 / 256) / temprate / (50/temprate + 1) ; ARR = temp - 1; CCR1 = temp / 2; 两个 TIMER 计数时钟是相同的,所以产生的脉冲是同相位的。但因为其中一个预先分频要慢细分数,所以产生中断的速度等于步进电机整步速度。这样中断的速度就降低了细分倍。如果对步数精度要求不高,可以将预分频倍数进一步提高,这样可以让电机转数步,才产生一个中断。
  • 热度 4
    2020-8-7 16:26
    621 次阅读|
    0 个评论
    使用一个空闲不用的定时器,做如下设置,预分频设为0, 周期设置为 55520-1 /* TIM7 init function */ static void MX_TIM7_Init(void) { TIM_MasterConfigTypeDef sMasterConfig; htim7.Instance = TIM7; htim7.Init.Prescaler = 0; htim7.Init.CounterMode = TIM_COUNTERMODE_UP; htim7.Init.Period = 65519; htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&htim7) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } 另外编写一个 delay_us的函数 /* 最大us数为 1356us */ inline void Delay_us(uint16_t us){ CNT = 0; HAL_TIM_Base_Start(&htim7); CNT < ((uint16_t)48 * us - 1)); } 调用时,将定时计数器清零,然后启动定时器,等待计数器达到设定的值后返回。 这里的时钟频率 PCLK为48M,计数器设定值为 48*us数。使用时注意这个数不要超过在period中的设定值。
  • 热度 2
    2020-7-23 16:20
    173 次阅读|
    0 个评论
    转载自 https://www.cnblogs.com/qiyuexin/p/8921718.html 目录 FAULTMASK PRIMASK BASEPRI BASEPRI_MAX 正文 1、总开关 每个CPU有一个中断总开关。通过CPU中断控制寄存器实现。Cortex-M的中断控制寄存器包括:FAULTMASK、PRIMASK、BASEPRI、BASEPRI_MAX。总开关的本质是变更当前执行优先级,根据Cortex-M的架构设计,只有优先级高于当前执行优先级的中断或异常才能抢占CPU。 回到顶部 FAULTMASK 设置为1后关闭所有中断和异常,包括HardFault异常,只有NMI和Reset可以得到响应。 回到顶部 PRIMASK 设置为1后关闭所有中断和除了HardFault异常外的所有其他异常,只有NMI、Reset和HardFault可以得到响应。 回到顶部 BASEPRI 设置为n后,屏蔽所有优先级数值大于等于n的中断和异常。Cortex-M的优先级数值越大其优先级越低。 回到顶部 BASEPRI_MAX 和BASEPRI类似,但有个限制,即后写入的优先级数值要比当前的BASEPRI值小才会起作用,否则不起作用。影响范围最广,影响CPU内的所有中断源。 事实上BASEPRI_MAX和BASSEPRI是操作同一个寄存器,不过BASEPRI_MAX是一个条件写指令,可以通过下列等效功能代码理解: // atomic related functions for unittest. extern uint8_t atomic_BASEPRI; // 用来模拟 BASEPRI 的值 // BASEPRI 设置 static inline uint8_t __set_BASEPRI(uint8_t prio) { atomic_BASEPRI = prio; } // BASEPRI_MAX 设置 static inline uint8_t __set_BASEPRI_MAX(uint8_t prio) { prio)) { atomic_BASEPRI = prio; } } 疑问:线程模式下,当前优先级和中断优先级的抢占优先级相同,但中断的子优先级比当前子优先级高,会怎么样?当前优先级也分抢占优先级和子优先级吗? 2、分开关 Cortex-M包括一个嵌套向量中断控制器NVIC,每个外设在NVIC中都有一个对应的位,用来控制该外设的中断。 ISER寄存器中外设对应位为1打开中断。 ICER寄存器中外设对应位为1关闭中断。 分开关只影响特定外设的中断。 3、源开关 外设通常有多个中断源,如接收到数据、发送完成、接收超时等等。外设通常提供中断使能寄存器控制哪些中断源产生时要向上汇报(向分开关汇报)。源开关与特定的外设相关,不同的外设会有不同的中断,有不同的中断控制寄存器。有些外设本身有总开关,该总开关控制该外设的所有中断。 源开关影响范围最窄,仅影响外设的某一种中断源。
  • 热度 1
    2020-7-5 14:42
    861 次阅读|
    0 个评论
    【不用开发板学习STM32】一般流水灯实验(文末获取代码及工程文件)
    • 实验环境 本次实验是通过Proteus+MDK一起模拟完成的。Proteus模拟实际电路,MDK编译代码。Proteus版本是8.9,MDK版本是5.21。需要注意的是,Proteus需要安装8.8以上版本,器件库里面要支持STM32F103C6。 • 实验目的 通过点亮三个LED,我们俗称的流水灯,来了解STM32的GPIO是怎么配置的。我们实验设置了Systick,即系统滴答时钟,延时也是通过这个滴答时钟来配置的,可以通过这个实验学习一下,怎么配置Systick,以及Systick中断怎么用。 • 主控: STM32F103C6(本来想用C8的,但是Proteus只有C6,本质上只有Flash和SRAM大小的区别,所有没有必要纠结) • 时钟: 没有用外部晶振,因为Proteus只支持一种时钟树,所以这里采用内部晶振,做实验够了。 • 复位电路: 复位电路如图,包含了上电复位电路一个10K电阻(图上用的是100K实际应该都是可以的)+一个100nF电容。按键复位电路,包含了一个自复位按键,按下后,RST管脚就会短路到GND,MCU就会复位。 • IO说明: 我们利用PA1、PA2、PA3来分别控制3个LED灯,输出低电平的时候,LED灯点亮。 • 代码目录概述: APP文件夹:主要包含应用函数的.C文件。 BSP文件夹:主要包含底层硬件驱动的.C文件。 MDK-ARM文件夹:主要包含STM32的启动的.S文件。 StdPeriph_Driver文件夹:主要包含ST官方提供的标准外设驱动.C文件(不是HAL库哦)。 CMSIS文件夹:系统内核配置文件,标准库自带的。 • 代码内容概述: ↓↓↓ GPIO初始化,先打开GPIOA的时钟,然后把PA1、PA2、PA3设置成推挽输出,代码如下: GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = LED1_Pin | LED2_Pin | LED3_Pin; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); ↓↓↓ Systick也要初始化,这里滴答时钟设置成1ms进一次中断,代码如下: void bsp_InitSysTick(void) { if (SysTick_Config(SystemCoreClock / 1000)) { /* Capture error */ while (1); } } ↓↓↓这里我们使用的是内部时钟,所以在初始化外设后还要把MCU设置成使用内部时钟,代码如下: void RCC_Configuration(void) { RCC_DeInit(); RCC_HSICmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET); RCC_HCLKConfig(RCC_SYSCLK_Div1); RCC_PCLK1Config(RCC_HCLK_Div2); RCC_PCLK2Config(RCC_HCLK_Div1); RCC_ADCCLKConfig(RCC_PCLK2_Div4); RCC_PLLConfig(RCC_PLLSource_HSI_Div2,RCC_PLLMul_10); RCC_PLLCmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); while(RCC_GetSYSCLKSource() != 0x08); } ↓↓↓ 更详细代码及工程文件,关注回复编号2001就能获取!!
相关资源
广告