记录stm32g431kbt6 编写SPI以及USB HID通信

文章讲述了在STM32单片机上遇到的USBHID通信、SPI读写及LCD显示之间的冲突问题。作者尝试通过禁用USB中断并在SPI操作后恢复来解决,但未成功。后来发现是栈区大小不足导致的代码溢出问题,增大栈区后问题得到解决。此外,还讨论了LCD初始化、延时函数实现、运算放大器烧毁以及电源管理等方面的内容。
摘要由CSDN通过智能技术生成

这里需要考虑多个任务的问题,类似PC上的操作系统,stm32单片机可以用调度器。重要的就是用一个定时器产生中断来作为时标,一个时标完成一个任务,任务运行时间不宜超过时标间隔,且避免同时进行多个任务。长时间的任务可以通过DMA来实现。22.

22. 8.15 (还没放暑假 (|| ~ , ~|| ) 

现在主要就是USB HID通信与SPI写读以及LCD的问题,这几个之间有冲突,一边写/读SPI,一边响应USB,会造成stm32不知道进入哪里死循环,哎。上位机有时候可以识别USB,有时候PC直接无法识别。(有一个bug,就是USB插入后,我有一个初始值为0的变量会改变,很奇怪?)

现在想在进行SPI写和读的时候将USB的中断全部禁止,SPI写完后在使能USB中断,但貌似不行,还是有错误。打算用定时器TIM1来做个时标,然后根据这个时标分配任务。

CubeMX配置定时器1中断,update interrupte 与break interrupt 的区别???

 void TIM3_IRQHandler(void)   首先进入中断函数
 HAL_TIM_IRQHandler(&htim2);之后进入定时器中断处理函数
判断产生的是哪一类定时器中断(溢出中断/PWM中断.....) 和定时器通道
 void HAL_TIM_PeriodElapsedCallback(&htim2);    进入相对应中断回调函数
在中断回调函数中添加用户代码。

设计代码架构,用时标的方法。

问题:添加定时器TIM1中断,USB HID连不上了。

可能是USB中断与定时器中断有冲突导致。

在默认的模板工程里,一般使用如下的方式实现延迟函数。

参考 STM32 USB无法连接电脑_cyang812的博客-CSDN博客https://blog.csdn.net/u011303443/article/details/78735808


__weak uint32_t HAL_GetTick(void)
{
  return uwTick;
}

__weak void HAL_Delay(__IO uint32_t Delay)
{
  uint32_t tickstart = 0U;
  tickstart = HAL_GetTick();
  while((HAL_GetTick() - tickstart) < Delay)
  {
  }
}

而在 USB 项目中,需要使用如下的方式实现延时函数。

void HAL_Delay(__IO uint32_t Delay)
{
  while(Delay) 
  {
    if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) 
    {
      Delay--;
    }
  }
}

这两种方式都可以实现基本的延时功能,都是使用的 SysTick 定时器来实现,也都是使用 while() 来进行条件判断,条件不满足,即计时到了指定的延时后退出 while() 。区别在于,第一种方式,进行条件判断的变量 uwTick 在 SysTick 的中断函数中进行加一操作,即如下代码:

__weak void HAL_IncTick(void)
{
  uwTick++;
}

void SysTick_Handler(void)
{
  HAL_IncTick();
}

而第二种方式,进行 while() 条件判断的变量 Delay 是不依赖于 SysTick 中断函数进行改变的,而是直接在这个函数中进行判断,等待寄存器数值改变,延时 1ms 后,对 Delay 进行减一操作。

默认的实现方式依赖于 SysTick 中断函数void SysTick_Handler(void),而在使用 USB 功能时,USB的操作本身就是需要在中断函数 void OTG_FS_IRQHandler(void) 中进行的。可能由于对不同中断函数的处理,导致了时间上的错误,从而电脑无法正确进行枚举操作。

USB 部分是在 usbd_conf.c 文件中的 void USBD_LL_Delay(uint32_t Delay) 函数中进行延时函数的调用的,如下所示:

void USBD_LL_Delay(uint32_t Delay)
{
  HAL_Delay(Delay);
}

看一下中断文件stm32fxxx_it.c里面的USB_LP_IRQHandler(void)

/**
  * @brief This function handles USB low priority interrupt remap.
  */

void USB_LP_IRQHandler(void)
{
  /* USER CODE BEGIN USB_LP_IRQn 0 */

  /* USER CODE END USB_LP_IRQn 0 */
  HAL_PCD_IRQHandler(&hpcd_USB_FS);
  /* USER CODE BEGIN USB_LP_IRQn 1 */

  /* USER CODE END USB_LP_IRQn 1 */
}

中断优先级设置函数 HAL_NVIC_SetPriority

(用Cubemx生成stm32代码,USB Custom HID)

在 usbd_conf.c中

void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
{
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  if(pcdHandle->Instance==USB)
  {
  /* USER CODE BEGIN USB_MspInit 0 */

  /* USER CODE END USB_MspInit 0 */

  /** Initializes the peripherals clocks
  */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
    PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }

    /* Peripheral clock enable */
    __HAL_RCC_USB_CLK_ENABLE();

    /* Peripheral interrupt init */
    HAL_NVIC_SetPriority(USB_LP_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USB_LP_IRQn);

  /* USER CODE BEGIN USB_MspInit 1 */

  /* USER CODE END USB_MspInit 1 */
  }
}

定时器优先级设置 tim.c中

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspInit 0 */

  /* USER CODE END TIM1_MspInit 0 */
    /* TIM1 clock enable */
    __HAL_RCC_TIM1_CLK_ENABLE();

    /* TIM1 interrupt Init */
    //HAL_NVIC_SetPriority(TIM1_BRK_TIM15_IRQn, 0, 0);
    //HAL_NVIC_EnableIRQ(TIM1_BRK_TIM15_IRQn);

  /* USER CODE BEGIN TIM1_MspInit 1 */
        HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);

  /* USER CODE END TIM1_MspInit 1 */
  }
}

更改优先级还是不行,先插入USB,定时器中断没有反应啊。

给改定时器中断时长试试。原先设定为10ms。

8.17

早上DDS还有输出的,可恶。

现在DDS无法启动,没有输出波形读取寄存器,数据返回正确。很奇怪的是,我只加了一段读取0x801E寄存器的代码,USB就无法识别,可是那段代码要等到USB发出命令才执行。我加了一段需要判别条件的代码,USB也会无法识别。真是艹了狗了,不知道该怎么办。需要版本管理一下。现在主要问题是DDS没有输出,之前也碰到过,貌似是reset时间不够,没有完全复位???,但是今天掉电时间长了,之后再启动还是没有输出,佛了。想锤人。

stm32自己还会复位的(应该是不小心弄断电了),很奇怪,再测量其输入晶振波形的时候。12MHz晶振没有波形,电压也很小,估计是晶振问题。

晚上看USB HID协议,如何通信,琢磨琢磨。

8.19

昨天晚上把代码的栈区扩大了,从原来的0x200(512Byte) 扩大到了 0x800(2048Byte),然后可以正常运行了。应该是栈区不够,导致代码溢出的问题,定时器可以正常工作,USB连接也正常。哎,琢磨了一个礼拜,以为是USB中断的问题,原来是代码容量的问题,修改了一个栈区就好了。

不过现在lcd屏显示还是有HAL_Delay(2) 2ms延时。还有还是需要考虑 USB _HID中断问题的,多任务处理。

现在做一个延时启动。

版本管理很重要!!!改一个就要调试,不要改太多后再调试。

lcd1602液晶显示屏更新的话,因为我是四线传输,而且只写不读,所以lcd1602中的RW就接地。

lcd1602坑也不少。

主要就是四线配置问题,以及时间问题。

四线配置我是这样配的:

配置四线模式只要输入0x02就可以了,后面就默认四线传输。

void lcd_init(void)
{
    uint8_t cmd;
        
    HAL_Delay(50);  // wait for >40ms
    
    //HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, GPIO_PIN_SET);
    //HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, GPIO_PIN_SET);

    
    HAL_Delay(10);
    
/***
    cmd = 0x30;
    lcd_send_cmd (cmd);
    HAL_Delay(10);  // wait for >4.1ms
    lcd_send_cmd (cmd);
    HAL_Delay(5);  // wait for >100us
    lcd_send_cmd (cmd);
    HAL_Delay(5);
    cmd = 0x20;
    lcd_send_cmd (cmd);  // 4bit mode
    HAL_Delay(10);
***/    

  // dislay initialisation
    
    lcd_send_cmd(0x02); // Function set --> DL=0 (4 bit mode), N = 1 (2 line display) F = 0 (5x8 characters)
    //0x02设置4线模式
    //lcd_send_cmd(0x28);
    //HAL_Delay(2);

    cmd = 0x08;
    lcd_send_cmd(cmd); //Display on/off control --> D=0,C=0, B=0  ---> display off
    HAL_Delay(2);
    cmd = 0x01;
    lcd_send_cmd(cmd);  // clear display
    HAL_Delay(2);
    //HAL_Delay(1);
    cmd =  0x06;
    lcd_send_cmd(cmd); //Entry mode set --> I/D = 1 (increment cursor) & S = 0 (no shift)
    HAL_Delay(2);
    cmd = 0x0C;
    lcd_send_cmd(cmd); //Display on/off control --> D = 1, C and B = 0. (Cursor and blink, last two bits)
    HAL_Delay(2);    
}
 

其实lcd1602更新一个文字不用太久时间(ms级别)查看数据手册可以知道只要ns就可以了。为什么之前加了延时2ms是因为lcd1602有个清除命令,清除命令用的是lcd1602里面的时钟,比我的stm32 8MHz时钟慢得多。导致它还没有清除完,我就开始写入了,这样就导致lcd1602显示乱码,虽然现在动动它的线还会乱码,不知道问什么,线太松动?

现在对比度显示正常,我在VO引脚上连了1.78KΩ的电阻,它里面应该有个上拉电阻。VO引脚电压越低,对比度越高,接地就是两排黑色点阵的块,看不到文字,接VCC就是太亮了。之前接了个2KΩ电阻,VO引脚电压是1.45V(VCC = 3.3V)(为什么3.3V的lcd1602比5V的贵,不理解),有点虚亮,对比度太高。现在接了1.78K的电阻就好很多,VO电压为0.95V???

8.20

增加了延时开启和关闭功能,先想将trigger1和trigger2用两个定时器通道TIM2_CH4和TIM3_CH1同步输出,两个定时器同步。

8.27

电路板烧掉了,GG。实验的时候突然噗呲一下,实验室断电了,然后9v1.5A电源适配器烧掉了,板子都短路了。

9.13

中秋回来继续搞。

电源3.3VSCT2452烧坏了,4个OPA4197的2,3,4引脚和11,12,13引脚短路了。是不是因为输入都接了0欧姆,然后烧掉的时候电流太大,导致芯片烧掉了。(这几天把电路版图再改改)。

虎年本命年倒霉啊!!!

想看一下OPA4197内部结构,看看到底是哪里不对。

了解下运算放大器各个参数,想知道其内部结构。TI 的E2E论坛不错。

听老师说放大器输入端在实际中运用中不能直接接地,不能连0欧姆电阻然后接地,不知道对不对。有的运算放大器内部有补偿电阻电路,其偏置电流Ib很小,与失调电流一个数量级,OPA4197的Ib就+-5pA(内部有电流源)。没有内部补偿电阻电路的运算放大器其偏置电流Ib就很大,需要外部电阻补偿,R= R//R2.

实际设计时就按匹配电阻考虑。(我的4个OPA4197运放可能因为输入端直接接了0Ω电阻到地,导致都损坏,输入端短路,输入端与负电源引脚短路)还有SCT4252这个降压芯片不是很好,几次烧坏都有它。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
引用中的代码是USB插入后主机进行枚举并复位USB的处理过程。在这段代码中,if语句检查是否发生了复位中断,如果发生了复位中断,则会进行一系列操作,包括清除复位标志、调用复位回调函数和设置地址为0。 引用中的代码是在USBD_CDC_Init函数中动态分配内存给pdev->pClassData。 引用中的代码是HAL_PCD_MspInit函数的定义部分,其中会根据pcdHandle->Instance的值进行相应的处理。 根据提供的引用信息,HAL_PCD_IRQHandler(&hpcd_USB_FS)是用于处理USB FS(全速)的中断请求的函数调用。具体的实现细节需要查看HAL库的文档和源代码。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [STM32 USB复合设备编写](https://blog.csdn.net/aifuxun2845/article/details/102026435)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [记录stm32g431kbt6 编写SPI以及USB HID通信](https://blog.csdn.net/s_jk6652/article/details/126348126)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值