有没有哪位大侠知道HAL_SD的标准函数啊 我看HAL手册里没有啊。。。。。。

回复

问题困惑BlackHei 发起了问题 • 1 人关注 • 0 个回复 • 2376 次浏览 • 2015-03-06 16:28 • 来自相关话题

你们确定你的stm32cubemx的4.6.0版本能用?F4的时钟树外部晶振始终修改?

回复

问题困惑popdes 发起了问题 • 1 人关注 • 0 个回复 • 3351 次浏览 • 2015-02-28 20:20 • 来自相关话题

stm32F407通过dp83848与PC端通信成功,在ubuntu下仅可以ping通,但通信不成功

回复

问题困惑lx09110718 发起了问题 • 2 人关注 • 0 个回复 • 3539 次浏览 • 2015-02-09 17:02 • 来自相关话题

关于FreeRTOS的设置分析和官方例程实验

回复

软件教程admin 发起了问题 • 6 人关注 • 0 个回复 • 5869 次浏览 • 2014-12-31 17:17 • 来自相关话题

转载一篇usb_hid的文章,来自捷克的一个电子论坛,用google翻译的,耐心看吧

经验分享admin 发表了文章 • 0 个评论 • 6872 次浏览 • 2014-12-30 09:52 • 来自相关话题

国外的电子论坛的作品,捷克语,翻译来的...
今天的作品的内容是USB HID。 HID我们已经讨论过,它是USB设备的类别之一。的优点是,HID是Windows的一个通用的组成部分,因此,就不需要驱动器和连接到PC的装置。这就是为什么我喜欢的虚拟USB串口选择HID实施的第二个实际的例子。
介绍

HID,因为我们讨论了我的各种装备。你可以让鼠标套件,这将是在屏幕上平移光标(如演示套件为例)或键盘,它允许你打开文件直接写入测量值。然而,在实践中,往往你可能会使用HID称,自定义页面,因此,它不会是一个“正常的装置”,但他们没有把它定义将如何表现,让PC控制,并从设备接收数据为您服务。

HID具有除的优势,一些缺点。缺点是由于这类USB设备的定义。 HID主要用于与人沟通 - 这是非常缓慢的外设相比,今天的计算机。所以HID设备只发送少量数据和缓慢的。然而,对于我们的许多应用中可能是足够的。我注意到在事先有人试图实现使用HID类,例如,逻辑分析仪或示波器,然后是惊讶,收集的数据不能传送到PC上。相反地,HID是适合于需要测量温度,电压,或从时间到时间的设备,以要求其它的当前值,或甚至USB字符显示到不时发送一些值。应用程序通过ST“USB HID演示”很好地展示了与HID沟通的可能性。在PC上运行的USB HID演示应用程序,点击图标点亮LED也对套件,反之亦然,当你按下工具包,让你出现在屏幕上相应的变化。它也发送来自AD转换器的一个值。所以数据并不多,但是当你编写自己的程序在PC上,这样你就不必想知道一些特殊的USB驱动程序,当编写应用程序的PC将使用一个简单的通用库,你přilinkujete他们的计划。但它会发现,在未来的一部分。在这一部分中,您将验证使用的是USB HID演示的功能。


实现

正如上面写的,我用这个软件的ST(USB HID演示),但它必须设置。第一USB HID演示下载(链接在最后),并安装它。第一次运行之后(你翻译这个演示工具包和连接第二USB电缆连接到PC之前)设置如下:





巴赫到VariableInput1他是06!在VariableOutput实现我走了,但你当然可以使用D/ A转换器产生一个相应的电压。无论如何,你可以尝试一下功课,谁可以先做到这一点,所以获得STM32F的一个样本。

设置完成后,您可以切换到正常的图形模式,然后你可以转换演示。仍有一些bug(有些嗡嗡声使整数赋给指针,未作类型转换等,但你也知道,基切食者warnigy不这样做,因此,有些跟你说实话可以对其进行编辑),但更主要的是,它的作品。我希望如此。因为我还没有尝试过这种测量A / D转换器引脚PA1,但我希望它的工作原理(并要求确认在评论中,如果有人测试过)。

至于其他MCU的实施和自然再利用STM32F4探索套件,它通过两个USB线与PC连接,如部分描述了USB虚拟串口。即使这个演示应用程序是用Atollic TrueSTUDIO这样你就可以将它解压缩,并将其导入您的环境。我们试图编写应用程序,因此您可以在IAR和Keil使用它,但因为没有这些环境不目前在PC,所以我没有检查导入功能。

翻译应用程序启动调试TrueSTUDIO,它被装载到MCU固件后,您F8,这是你运行了该程序的简历。在PC应该跳的连接到新的硬件(HID)和枚举后的图标,你会看到“控制面板 - 系统 - 硬件 - 设备管理器”中,你开始一个新的USB设备列表的末尾。这只是验证USB HID正确介绍。然后您可以点击USB HID演示和挤压USER按钮(蓝色),以STM32F4探索套件,它应该工作。我的意思是,当你按下USER按钮,表格USB HID演示看看它是如何变成绿色圆圈,左,反之亦然,通过PC屏幕上的表单弹将点亮LED的套件。在屏幕上,它看起来像下图。





在SW细节

我出来的时候自然地从现有的演示,STM32F4探索,它实现了HID鼠标。然而,鼠标只发送数据,并且不接受任何东西,所以我不得不注册谱写新的功能USBD_HID_DataOut。注册我进行如下:


USBD_Class_cb_TypeDef USBD_HID_cb =
{
USBD_HID_Init,
USBD_HID_DeInit,
USBD_HID_Setup,
NULL, /[i]EP0_TxSent[/i]/
NULL, /[i]EP0_RxReady[/i]/
USBD_HID_DataIn, /[i]DataIn[/i]/
/[i] NULL,[/i]/
USBD_HID_DataOut, /[i]DataOut[/i]/
NULL, /[i]SOF [/i]/
NULL,
NULL,
USBD_HID_GetCfgDesc,
#ifdef USB_OTG_HS_CORE
USBD_HID_GetCfgDesc, /[i] use same config as per FS [/i]/
#endif
};

函数如下:


/**
* @brief USBD_HID_DataOut
* handle data OUT Stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
static uint8_t USBD_HID_DataOut (void *pdev, uint8_t epnum)
{
uint16_t USB_RecData_Cnt;
BitAction Led_State;
if (epnum == HID_OUT_EP)
{
/[i] Get the received data buffer and update the counter [/i]/
USB_RecData_Cnt = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_count;
/* USB data will be immediately processed, this allow next USB traffic being
NAKed till the end of the application Xfer */
if (((USB_OTG_CORE_HANDLE*)pdev)->dev.device_status == USB_OTG_CONFIGURED )
{
/[i] predpokladame ze delka = 2 bajty [/i]/
USB_OTG_ReadPacket((USB_OTG_CORE_HANDLE[i])pdev, [/i]Buffer, HID_OUT_PACKET);
/[i] process the report setting [/i]/
if (Buffer[1] == 0)
Led_State = Bit_RESET;
else
Led_State = Bit_SET;
switch (Buffer[0])
{
case 1: /[i] Led 1 [/i]/
if (Led_State != Bit_RESET)
STM32F4_Discovery_LEDOn(LED3);
else
STM32F4_Discovery_LEDOff(LED3);
break;
case 2: /[i] Led 2 [/i]/
if (Led_State != Bit_RESET)
STM32F4_Discovery_LEDOn(LED4);
else
STM32F4_Discovery_LEDOff(LED4);
break;
case 3: /[i] Led 3 [/i]/
if (Led_State != Bit_RESET)
STM32F4_Discovery_LEDOn(LED5);
else
STM32F4_Discovery_LEDOff(LED5);
break;
case 4: /[i] Led 4 [/i]/
if (Led_State != Bit_RESET)
STM32F4_Discovery_LEDOn(LED6);
else
STM32F4_Discovery_LEDOff(LED6);
break;
default:
STM32F4_Discovery_LEDOff(LED3); /[i] oranzova [/i]/
STM32F4_Discovery_LEDOff(LED4); /[i] zelena [/i]/
STM32F4_Discovery_LEDOff(LED5); /[i] cervena [/i]/
STM32F4_Discovery_LEDOff(LED6); /[i] modra [/i]/
break;
}
/[i] Prepare Out endpoint to receive next packet [/i]/
DCD_EP_PrepareRx(pdev,
HID_OUT_EP,
(uint8_t*)(Buffer),
HID_OUT_PACKET);
}
}
return USBD_OK;
}

你怎么看你自己的代码,因此函数从PC直接处理收到的报告,并没有设置按试剂盒的LED。但是,这是问题的一个方面,即在数据的方向从PC向USB设备。但你也想从一个工具包,以PC发送数据(没有多少那里,只有用户按下按钮,但我们无论如何写)。观察整个事情在main()。


/**
* @brief Main program.
* @param None
* @retval None
*/
int main(void)
{
STM32F4_Discovery_LEDInit(LED3);
STM32F4_Discovery_LEDInit(LED4);
STM32F4_Discovery_LEDInit(LED5);
STM32F4_Discovery_LEDInit(LED6);
STM32F4_Discovery_PBInit(BUTTON_USER, BUTTON_MODE_GPIO);

/[i] zapneme LED3 [/i]/
STM32F4_Discovery_LEDOn(LED3); /[i] oranzova [/i]/
Delay(0xFFFF);
STM32F4_Discovery_LEDOff(LED3); /[i] oranzova [/i]/

USBD_Init(&USB_OTG_dev,
#ifdef USE_USB_OTG_HS
USB_OTG_HS_CORE_ID,
#else
USB_OTG_FS_CORE_ID,
#endif
&USR_desc,
&USBD_HID_cb,
&USR_cb);

Init_ADC_Reading();
while (1)
{
if (STM32F4_Discovery_PBGetState(BUTTON_USER) == Bit_SET)
{
/[i] STM32F4_Discovery_LEDOn(LED3); oranzova - debug only [/i]/
if (UserButtonPressed != 0x01)
{
/[i] new action [/i]/
UserButtonPressed = 0x01;
Delay(0xFF);
Buffer[0]=0x05; /[i] report cislo 5 [/i]/
Buffer[1]=0x01;
USBD_HID_SendReport (&USB_OTG_dev, Buffer, 2);
}
}
else
{
/[i] STM32F4_Discovery_LEDOff(LED3); oranzova - debug only[/i]/
if (UserButtonPressed != 0x00)
{
/[i] new action [/i]/
UserButtonPressed = 0x00;
Delay(0xFF);
Buffer[0]=0x05; /[i] report cislo 5 [/i]/
Buffer[1]=0x00;
USBD_HID_SendReport (&USB_OTG_dev, Buffer, 2);
}
}
}
}

操作通信,也不得不写,而不是原来的一个新的报告描述符。新如下所示。


__ALIGN_BEGIN static uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] __ALIGN_END =
{
0x06, 0xFF, 0x00, /[i] USAGE_PAGE (Vendor Page: 0xFF00) [/i]/
0x09, 0x01, /[i] USAGE (Demo Kit) [/i]/
0xA1, 0x01, /[i] COLLECTION (Application) [/i]/
/[i] 6 [/i]/
/[i] Led 1 [/i]/
0x85, 0x01, /[i] REPORT_ID (1) [/i]/
0x09, 0x01, /[i] USAGE (LED 1) [/i]/
0x15, 0x00, /[i] LOGICAL_MINIMUM (0) [/i]/
0x25, 0x01, /[i] LOGICAL_MAXIMUM (1) [/i]/
0x75, 0x08, /[i] REPORT_SIZE (8) [/i]/
0x95, 0x01, /[i] REPORT_COUNT (1) [/i]/
0xB1, 0x82, /[i] FEATURE (Data,Var,Abs,Vol) [/i]/
0x85, 0x01, /[i] REPORT_ID (1) [/i]/
0x09, 0x01, /[i] USAGE (LED 1) [/i]/
0x91, 0x82, /[i] OUTPUT (Data,Var,Abs,Vol) [/i]/
/[i] 26 [/i]/
/[i] Led 2 [/i]/
0x85, 0x02, /[i] REPORT_ID 2 [/i]/
0x09, 0x02, /[i] USAGE (LED 2) [/i]/
0x15, 0x00, /[i] LOGICAL_MINIMUM (0) [/i]/
0x25, 0x01, /[i] LOGICAL_MAXIMUM (1) [/i]/
0x75, 0x08, /[i] REPORT_SIZE (8) [/i]/
0x95, 0x01, /[i] REPORT_COUNT (1) [/i]/
0xB1, 0x82, /[i] FEATURE (Data,Var,Abs,Vol) [/i]/
0x85, 0x02, /[i] REPORT_ID (2) [/i]/
0x09, 0x02, /[i] USAGE (LED 2) [/i]/
0x91, 0x82, /[i] OUTPUT (Data,Var,Abs,Vol) [/i]/
/[i] 46 [/i]/
/[i] Led 3 [/i]/
0x85, 0x03, /[i] REPORT_ID (3) [/i]/
0x09, 0x03, /[i] USAGE (LED 3) [/i]/
0x15, 0x00, /[i] LOGICAL_MINIMUM (0) [/i]/
0x25, 0x01, /[i] LOGICAL_MAXIMUM (1) [/i]/
0x75, 0x08, /[i] REPORT_SIZE (8) [/i]/
0x95, 0x01, /[i] REPORT_COUNT (1) [/i]/
0xB1, 0x82, /[i] FEATURE (Data,Var,Abs,Vol) [/i]/
0x85, 0x03, /[i] REPORT_ID (3) [/i]/
0x09, 0x03, /[i] USAGE (LED 3) [/i]/
0x91, 0x82, /[i] OUTPUT (Data,Var,Abs,Vol) [/i]/
/[i] 66 [/i]/
/[i] Led 4 [/i]/
0x85, 0x04, /[i] REPORT_ID 4) [/i]/
0x09, 0x04, /[i] USAGE (LED 4) [/i]/
0x15, 0x00, /[i] LOGICAL_MINIMUM (0) [/i]/
0x25, 0x01, /[i] LOGICAL_MAXIMUM (1) [/i]/
0x75, 0x08, /[i] REPORT_SIZE (8) [/i]/
0x95, 0x01, /[i] REPORT_COUNT (1) [/i]/
0xB1, 0x82, /[i] FEATURE (Data,Var,Abs,Vol) [/i]/
0x85, 0x04, /[i] REPORT_ID (4) [/i]/
0x09, 0x04, /[i] USAGE (LED 4) [/i]/
0x91, 0x82, /[i] OUTPUT (Data,Var,Abs,Vol) [/i]/
/[i] 86 [/i]/
/[i] key USER Button [/i]/
0x85, 0x05, /[i] REPORT_ID (5) [/i]/
0x09, 0x05, /[i] USAGE (USER Button) [/i]/
0x15, 0x00, /[i] LOGICAL_MINIMUM (0) [/i]/
0x25, 0x01, /[i] LOGICAL_MAXIMUM (1) [/i]/
0x75, 0x01, /[i] REPORT_SIZE (1) [/i]/
0x81, 0x82, /[i] INPUT (Data,Var,Abs,Vol) [/i]/
0x09, 0x05, /[i] USAGE (USER Button) [/i]/
0x75, 0x01, /[i] REPORT_SIZE (1) [/i]/
0xb1, 0x82, /[i] FEATURE (Data,Var,Abs,Vol) [/i]/
0x75, 0x07, /[i] REPORT_SIZE (7) [/i]/
0x81, 0x83, /[i] INPUT (Cnst,Var,Abs,Vol) [/i]/
0x85, 0x05, /[i] REPORT_ID (5) [/i]/
0x75, 0x07, /[i] REPORT_SIZE (7) [/i]/
0xb1, 0x83, /[i] FEATURE (Cnst,Var,Abs,Vol) [/i]/
/[i] 114 [/i]/
/[i] ADC IN [/i]/
0x85, 0x06, /[i] REPORT_ID (6) [/i]/
0x09, 0x07, /[i] USAGE (ADC IN) [/i]/
0x15, 0x00, /[i] LOGICAL_MINIMUM (0) [/i]/
0x26, 0xff, 0x00, /[i] LOGICAL_MAXIMUM (255) [/i]/
0x75, 0x08, /[i] REPORT_SIZE (8) [/i]/
0x81, 0x82, /[i] INPUT (Data,Var,Abs,Vol) [/i]/
0x85, 0x06, /[i] REPORT_ID (6) [/i]/
0x09, 0x06, /[i] USAGE (ADC in) [/i]/
0xb1, 0x82, /[i] FEATURE (Data,Var,Abs,Vol) [/i]/
/[i] 133 [/i]/
0xc0 /[i] END_COLLECTION [/i]/
}; /[i] CustomHID_ReportDescriptor [/i]/

正如你可以从报告的描述看,所以要控制每一个元素,都必须在报告中恰当的描述。当然还有另一种解决方案 - 编写需要一个30字节的数据包的长度只有一个报告,内容你自己定义一个通用的元素。但是,如果我想使用USB HID演示,所以我不得不坚持要求该报告,在上述声明中表示标准。

结论

我有这个计划,努力不够。而唯一的原因是我的狗屎当我忽视的是,在定义中描述的设备我有一个不正确长度的描述,当然,这导致了他的中间枚举下降。哦耶。好吧,我终于,两天后,他擦额头出汗出现。所以我希望至少有一小的奖励将是我希望这是USB的第一实施HID自定义页面STM32F4探索套件的世界。

接下来的时间,我们将展示如何使用Visual Studio的C#写的东西,如USB HID演示从ST。

如果你认为你的文字和连接演示程序值得你欣赏,你可以提交你的资助。谢谢你提前给大家!你会支持其他文章的出现。
参考

材料HID这里找到。
USB HID演示你下载的ST网站在这里。

这项工作的压缩项目都可以在这里找到。

入门STM32F4套件第一个链接(开发环境等)
入门STM32F4第二连接套件(USB首页)
入门STM32F4第三连接套件(USB枚举)
入门STM32F4套件第四连接(USB虚拟COM口)
Modifikce USB HID的STM32F103链接
入门STM32F4套件第五连杆(端口名称,选择功能)
与STM32F4套件第六连杆(VGA显示器)入门

补充

尽管如此,我忘了写了A / D转换器,一个试剂盒PC的价值将中断触发时,ADC转换完成的文本。因此,它可以在处理程序的中断中找到。

本文转自:http://mcu.cz/comment-n2848.html

本文配套的图示软件,在本站百度网盘中可以找到 !请自行下载 ! 查看全部
国外的电子论坛的作品,捷克语,翻译来的...
今天的作品的内容是USB HID。 HID我们已经讨论过,它是USB设备的类别之一。的优点是,HID是Windows的一个通用的组成部分,因此,就不需要驱动器和连接到PC的装置。这就是为什么我喜欢的虚拟USB串口选择HID实施的第二个实际的例子。
介绍

HID,因为我们讨论了我的各种装备。你可以让鼠标套件,这将是在屏幕上平移光标(如演示套件为例)或键盘,它允许你打开文件直接写入测量值。然而,在实践中,往往你可能会使用HID称,自定义页面,因此,它不会是一个“正常的装置”,但他们没有把它定义将如何表现,让PC控制,并从设备接收数据为您服务。

HID具有除的优势,一些缺点。缺点是由于这类USB设备的定义。 HID主要用于与人沟通 - 这是非常缓慢的外设相比,今天的计算机。所以HID设备只发送少量数据和缓慢的。然而,对于我们的许多应用中可能是足够的。我注意到在事先有人试图实现使用HID类,例如,逻辑分析仪或示波器,然后是惊讶,收集的数据不能传送到PC上。相反地,HID是适合于需要测量温度,电压,或从时间到时间的设备,以要求其它的当前值,或甚至USB字符显示到不时发送一些值。应用程序通过ST“USB HID演示”很好地展示了与HID沟通的可能性。在PC上运行的USB HID演示应用程序,点击图标点亮LED也对套件,反之亦然,当你按下工具包,让你出现在屏幕上相应的变化。它也发送来自AD转换器的一个值。所以数据并不多,但是当你编写自己的程序在PC上,这样你就不必想知道一些特殊的USB驱动程序,当编写应用程序的PC将使用一个简单的通用库,你přilinkujete他们的计划。但它会发现,在未来的一部分。在这一部分中,您将验证使用的是USB HID演示的功能。


实现

正如上面写的,我用这个软件的ST(USB HID演示),但它必须设置。第一USB HID演示下载(链接在最后),并安装它。第一次运行之后(你翻译这个演示工具包和连接第二USB电缆连接到PC之前)设置如下:

hiddemonstrator.png

巴赫到VariableInput1他是06!在VariableOutput实现我走了,但你当然可以使用D/ A转换器产生一个相应的电压。无论如何,你可以尝试一下功课,谁可以先做到这一点,所以获得STM32F的一个样本。

设置完成后,您可以切换到正常的图形模式,然后你可以转换演示。仍有一些bug(有些嗡嗡声使整数赋给指针,未作类型转换等,但你也知道,基切食者warnigy不这样做,因此,有些跟你说实话可以对其进行编辑),但更主要的是,它的作品。我希望如此。因为我还没有尝试过这种测量A / D转换器引脚PA1,但我希望它的工作原理(并要求确认在评论中,如果有人测试过)。

至于其他MCU的实施和自然再利用STM32F4探索套件,它通过两个USB线与PC连接,如部分描述了USB虚拟串口。即使这个演示应用程序是用Atollic TrueSTUDIO这样你就可以将它解压缩,并将其导入您的环境。我们试图编写应用程序,因此您可以在IAR和Keil使用它,但因为没有这些环境不目前在PC,所以我没有检查导入功能。

翻译应用程序启动调试TrueSTUDIO,它被装载到MCU固件后,您F8,这是你运行了该程序的简历。在PC应该跳的连接到新的硬件(HID)和枚举后的图标,你会看到“控制面板 - 系统 - 硬件 - 设备管理器”中,你开始一个新的USB设备列表的末尾。这只是验证USB HID正确介绍。然后您可以点击USB HID演示和挤压USER按钮(蓝色),以STM32F4探索套件,它应该工作。我的意思是,当你按下USER按钮,表格USB HID演示看看它是如何变成绿色圆圈,左,反之亦然,通过PC屏幕上的表单弹将点亮LED的套件。在屏幕上,它看起来像下图。

hiddemonstrator2.png

在SW细节

我出来的时候自然地从现有的演示,STM32F4探索,它实现了HID鼠标。然而,鼠标只发送数据,并且不接受任何东西,所以我不得不注册谱写新的功能USBD_HID_DataOut。注册我进行如下:


USBD_Class_cb_TypeDef USBD_HID_cb =
{
USBD_HID_Init,
USBD_HID_DeInit,
USBD_HID_Setup,
NULL, /[i]EP0_TxSent[/i]/
NULL, /[i]EP0_RxReady[/i]/
USBD_HID_DataIn, /[i]DataIn[/i]/
/[i] NULL,[/i]/
USBD_HID_DataOut, /[i]DataOut[/i]/
NULL, /[i]SOF [/i]/
NULL,
NULL,
USBD_HID_GetCfgDesc,
#ifdef USB_OTG_HS_CORE
USBD_HID_GetCfgDesc, /[i] use same config as per FS [/i]/
#endif
};

函数如下:


/**
* @brief USBD_HID_DataOut
* handle data OUT Stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
static uint8_t USBD_HID_DataOut (void *pdev, uint8_t epnum)
{
uint16_t USB_RecData_Cnt;
BitAction Led_State;
if (epnum == HID_OUT_EP)
{
/[i] Get the received data buffer and update the counter [/i]/
USB_RecData_Cnt = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_count;
/* USB data will be immediately processed, this allow next USB traffic being
NAKed till the end of the application Xfer */
if (((USB_OTG_CORE_HANDLE*)pdev)->dev.device_status == USB_OTG_CONFIGURED )
{
/[i] predpokladame ze delka = 2 bajty [/i]/
USB_OTG_ReadPacket((USB_OTG_CORE_HANDLE[i])pdev, [/i]Buffer, HID_OUT_PACKET);
/[i] process the report setting [/i]/
if (Buffer[1] == 0)
Led_State = Bit_RESET;
else
Led_State = Bit_SET;
switch (Buffer[0])
{
case 1: /[i] Led 1 [/i]/
if (Led_State != Bit_RESET)
STM32F4_Discovery_LEDOn(LED3);
else
STM32F4_Discovery_LEDOff(LED3);
break;
case 2: /[i] Led 2 [/i]/
if (Led_State != Bit_RESET)
STM32F4_Discovery_LEDOn(LED4);
else
STM32F4_Discovery_LEDOff(LED4);
break;
case 3: /[i] Led 3 [/i]/
if (Led_State != Bit_RESET)
STM32F4_Discovery_LEDOn(LED5);
else
STM32F4_Discovery_LEDOff(LED5);
break;
case 4: /[i] Led 4 [/i]/
if (Led_State != Bit_RESET)
STM32F4_Discovery_LEDOn(LED6);
else
STM32F4_Discovery_LEDOff(LED6);
break;
default:
STM32F4_Discovery_LEDOff(LED3); /[i] oranzova [/i]/
STM32F4_Discovery_LEDOff(LED4); /[i] zelena [/i]/
STM32F4_Discovery_LEDOff(LED5); /[i] cervena [/i]/
STM32F4_Discovery_LEDOff(LED6); /[i] modra [/i]/
break;
}
/[i] Prepare Out endpoint to receive next packet [/i]/
DCD_EP_PrepareRx(pdev,
HID_OUT_EP,
(uint8_t*)(Buffer),
HID_OUT_PACKET);
}
}
return USBD_OK;
}

你怎么看你自己的代码,因此函数从PC直接处理收到的报告,并没有设置按试剂盒的LED。但是,这是问题的一个方面,即在数据的方向从PC向USB设备。但你也想从一个工具包,以PC发送数据(没有多少那里,只有用户按下按钮,但我们无论如何写)。观察整个事情在main()。


/**
* @brief Main program.
* @param None
* @retval None
*/
int main(void)
{
STM32F4_Discovery_LEDInit(LED3);
STM32F4_Discovery_LEDInit(LED4);
STM32F4_Discovery_LEDInit(LED5);
STM32F4_Discovery_LEDInit(LED6);
STM32F4_Discovery_PBInit(BUTTON_USER, BUTTON_MODE_GPIO);

/[i] zapneme LED3 [/i]/
STM32F4_Discovery_LEDOn(LED3); /[i] oranzova [/i]/
Delay(0xFFFF);
STM32F4_Discovery_LEDOff(LED3); /[i] oranzova [/i]/

USBD_Init(&USB_OTG_dev,
#ifdef USE_USB_OTG_HS
USB_OTG_HS_CORE_ID,
#else
USB_OTG_FS_CORE_ID,
#endif
&USR_desc,
&USBD_HID_cb,
&USR_cb);

Init_ADC_Reading();
while (1)
{
if (STM32F4_Discovery_PBGetState(BUTTON_USER) == Bit_SET)
{
/[i] STM32F4_Discovery_LEDOn(LED3); oranzova - debug only [/i]/
if (UserButtonPressed != 0x01)
{
/[i] new action [/i]/
UserButtonPressed = 0x01;
Delay(0xFF);
Buffer[0]=0x05; /[i] report cislo 5 [/i]/
Buffer[1]=0x01;
USBD_HID_SendReport (&USB_OTG_dev, Buffer, 2);
}
}
else
{
/[i] STM32F4_Discovery_LEDOff(LED3); oranzova - debug only[/i]/
if (UserButtonPressed != 0x00)
{
/[i] new action [/i]/
UserButtonPressed = 0x00;
Delay(0xFF);
Buffer[0]=0x05; /[i] report cislo 5 [/i]/
Buffer[1]=0x00;
USBD_HID_SendReport (&USB_OTG_dev, Buffer, 2);
}
}
}
}

操作通信,也不得不写,而不是原来的一个新的报告描述符。新如下所示。


__ALIGN_BEGIN static uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] __ALIGN_END =
{
0x06, 0xFF, 0x00, /[i] USAGE_PAGE (Vendor Page: 0xFF00) [/i]/
0x09, 0x01, /[i] USAGE (Demo Kit) [/i]/
0xA1, 0x01, /[i] COLLECTION (Application) [/i]/
/[i] 6 [/i]/
/[i] Led 1 [/i]/
0x85, 0x01, /[i] REPORT_ID (1) [/i]/
0x09, 0x01, /[i] USAGE (LED 1) [/i]/
0x15, 0x00, /[i] LOGICAL_MINIMUM (0) [/i]/
0x25, 0x01, /[i] LOGICAL_MAXIMUM (1) [/i]/
0x75, 0x08, /[i] REPORT_SIZE (8) [/i]/
0x95, 0x01, /[i] REPORT_COUNT (1) [/i]/
0xB1, 0x82, /[i] FEATURE (Data,Var,Abs,Vol) [/i]/
0x85, 0x01, /[i] REPORT_ID (1) [/i]/
0x09, 0x01, /[i] USAGE (LED 1) [/i]/
0x91, 0x82, /[i] OUTPUT (Data,Var,Abs,Vol) [/i]/
/[i] 26 [/i]/
/[i] Led 2 [/i]/
0x85, 0x02, /[i] REPORT_ID 2 [/i]/
0x09, 0x02, /[i] USAGE (LED 2) [/i]/
0x15, 0x00, /[i] LOGICAL_MINIMUM (0) [/i]/
0x25, 0x01, /[i] LOGICAL_MAXIMUM (1) [/i]/
0x75, 0x08, /[i] REPORT_SIZE (8) [/i]/
0x95, 0x01, /[i] REPORT_COUNT (1) [/i]/
0xB1, 0x82, /[i] FEATURE (Data,Var,Abs,Vol) [/i]/
0x85, 0x02, /[i] REPORT_ID (2) [/i]/
0x09, 0x02, /[i] USAGE (LED 2) [/i]/
0x91, 0x82, /[i] OUTPUT (Data,Var,Abs,Vol) [/i]/
/[i] 46 [/i]/
/[i] Led 3 [/i]/
0x85, 0x03, /[i] REPORT_ID (3) [/i]/
0x09, 0x03, /[i] USAGE (LED 3) [/i]/
0x15, 0x00, /[i] LOGICAL_MINIMUM (0) [/i]/
0x25, 0x01, /[i] LOGICAL_MAXIMUM (1) [/i]/
0x75, 0x08, /[i] REPORT_SIZE (8) [/i]/
0x95, 0x01, /[i] REPORT_COUNT (1) [/i]/
0xB1, 0x82, /[i] FEATURE (Data,Var,Abs,Vol) [/i]/
0x85, 0x03, /[i] REPORT_ID (3) [/i]/
0x09, 0x03, /[i] USAGE (LED 3) [/i]/
0x91, 0x82, /[i] OUTPUT (Data,Var,Abs,Vol) [/i]/
/[i] 66 [/i]/
/[i] Led 4 [/i]/
0x85, 0x04, /[i] REPORT_ID 4) [/i]/
0x09, 0x04, /[i] USAGE (LED 4) [/i]/
0x15, 0x00, /[i] LOGICAL_MINIMUM (0) [/i]/
0x25, 0x01, /[i] LOGICAL_MAXIMUM (1) [/i]/
0x75, 0x08, /[i] REPORT_SIZE (8) [/i]/
0x95, 0x01, /[i] REPORT_COUNT (1) [/i]/
0xB1, 0x82, /[i] FEATURE (Data,Var,Abs,Vol) [/i]/
0x85, 0x04, /[i] REPORT_ID (4) [/i]/
0x09, 0x04, /[i] USAGE (LED 4) [/i]/
0x91, 0x82, /[i] OUTPUT (Data,Var,Abs,Vol) [/i]/
/[i] 86 [/i]/
/[i] key USER Button [/i]/
0x85, 0x05, /[i] REPORT_ID (5) [/i]/
0x09, 0x05, /[i] USAGE (USER Button) [/i]/
0x15, 0x00, /[i] LOGICAL_MINIMUM (0) [/i]/
0x25, 0x01, /[i] LOGICAL_MAXIMUM (1) [/i]/
0x75, 0x01, /[i] REPORT_SIZE (1) [/i]/
0x81, 0x82, /[i] INPUT (Data,Var,Abs,Vol) [/i]/
0x09, 0x05, /[i] USAGE (USER Button) [/i]/
0x75, 0x01, /[i] REPORT_SIZE (1) [/i]/
0xb1, 0x82, /[i] FEATURE (Data,Var,Abs,Vol) [/i]/
0x75, 0x07, /[i] REPORT_SIZE (7) [/i]/
0x81, 0x83, /[i] INPUT (Cnst,Var,Abs,Vol) [/i]/
0x85, 0x05, /[i] REPORT_ID (5) [/i]/
0x75, 0x07, /[i] REPORT_SIZE (7) [/i]/
0xb1, 0x83, /[i] FEATURE (Cnst,Var,Abs,Vol) [/i]/
/[i] 114 [/i]/
/[i] ADC IN [/i]/
0x85, 0x06, /[i] REPORT_ID (6) [/i]/
0x09, 0x07, /[i] USAGE (ADC IN) [/i]/
0x15, 0x00, /[i] LOGICAL_MINIMUM (0) [/i]/
0x26, 0xff, 0x00, /[i] LOGICAL_MAXIMUM (255) [/i]/
0x75, 0x08, /[i] REPORT_SIZE (8) [/i]/
0x81, 0x82, /[i] INPUT (Data,Var,Abs,Vol) [/i]/
0x85, 0x06, /[i] REPORT_ID (6) [/i]/
0x09, 0x06, /[i] USAGE (ADC in) [/i]/
0xb1, 0x82, /[i] FEATURE (Data,Var,Abs,Vol) [/i]/
/[i] 133 [/i]/
0xc0 /[i] END_COLLECTION [/i]/
}; /[i] CustomHID_ReportDescriptor [/i]/

正如你可以从报告的描述看,所以要控制每一个元素,都必须在报告中恰当的描述。当然还有另一种解决方案 - 编写需要一个30字节的数据包的长度只有一个报告,内容你自己定义一个通用的元素。但是,如果我想使用USB HID演示,所以我不得不坚持要求该报告,在上述声明中表示标准。

结论

我有这个计划,努力不够。而唯一的原因是我的狗屎当我忽视的是,在定义中描述的设备我有一个不正确长度的描述,当然,这导致了他的中间枚举下降。哦耶。好吧,我终于,两天后,他擦额头出汗出现。所以我希望至少有一小的奖励将是我希望这是USB的第一实施HID自定义页面STM32F4探索套件的世界。

接下来的时间,我们将展示如何使用Visual Studio的C#写的东西,如USB HID演示从ST。

如果你认为你的文字和连接演示程序值得你欣赏,你可以提交你的资助。谢谢你提前给大家!你会支持其他文章的出现。
参考

材料HID这里找到。
USB HID演示你下载的ST网站在这里。

这项工作的压缩项目都可以在这里找到。

入门STM32F4套件第一个链接(开发环境等)
入门STM32F4第二连接套件(USB首页)
入门STM32F4第三连接套件(USB枚举)
入门STM32F4套件第四连接(USB虚拟COM口)
Modifikce USB HID的STM32F103链接
入门STM32F4套件第五连杆(端口名称,选择功能)
与STM32F4套件第六连杆(VGA显示器)入门

补充

尽管如此,我忘了写了A / D转换器,一个试剂盒PC的价值将中断触发时,ADC转换完成的文本。因此,它可以在处理程序的中断中找到。

本文转自:http://mcu.cz/comment-n2848.html



本文配套的图示软件,在本站百度网盘中可以找到 !请自行下载 !

分享:当串口com的端口号太大怎么办?下面教你解除串口端口占用

经验分享admin 发表了文章 • 0 个评论 • 5183 次浏览 • 2014-12-16 22:50 • 来自相关话题

大多数时候电脑的com口没用到但是com口的端口号却不会从小到大来.....
下面教你解除那些占着茅坑不拉屎的端口的方法
虽然现在串口使用的不多了,但是有的时候还是会用上,但是在我门偶尔要使用串口(COM口)的时候却发现,它总是提示被占用(在使用中),而程序又限定了端口号,这个是有我们只有想办法解决串口/COM端口被占用(在使用中)的问题了

第一,检查这个端口是不是有设备在使用,如果有,可以先断开这个设备,让开位置来

第二,也是常见的问题,被某些软件占用了,解决方法如下

点击左下角“开始”菜单——“运行”——输入“regedit”——点击“确定”,打开注册表编辑器。

依照这个路径打开“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\COM Name Arbiter”

删除右侧的“ComDb”值
双击comdb字样,弹出输入框,全选删除,ok
插入串口线,设备管理器里面删除掉此时的端口,或者修改为其他端口,若是删除的,则再次插入后自动变更. 查看全部
大多数时候电脑的com口没用到但是com口的端口号却不会从小到大来.....
下面教你解除那些占着茅坑不拉屎的端口的方法
虽然现在串口使用的不多了,但是有的时候还是会用上,但是在我门偶尔要使用串口(COM口)的时候却发现,它总是提示被占用(在使用中),而程序又限定了端口号,这个是有我们只有想办法解决串口/COM端口被占用(在使用中)的问题了

第一,检查这个端口是不是有设备在使用,如果有,可以先断开这个设备,让开位置来

第二,也是常见的问题,被某些软件占用了,解决方法如下

点击左下角“开始”菜单——“运行”——输入“regedit”——点击“确定”,打开注册表编辑器。

依照这个路径打开“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\COM Name Arbiter”

删除右侧的“ComDb”值
双击comdb字样,弹出输入框,全选删除,ok
插入串口线,设备管理器里面删除掉此时的端口,或者修改为其他端口,若是删除的,则再次插入后自动变更.

谈谈关于红外遥控接收程序的疑问?看到都在用中断处理,延时等待检测,没有效率可言

回复

问题困惑admin 发起了问题 • 2 人关注 • 0 个回复 • 3173 次浏览 • 2014-10-14 00:24 • 来自相关话题

stm32cube中文教程:TIM3定时,TIM1双通道计数器的实现

软件教程admin 发表了文章 • 0 个评论 • 9389 次浏览 • 2014-10-14 00:16 • 来自相关话题

本次利用了,stm32cubemx生成代码,稍微在main中添加得到
打开cubemx,先设置pinout选项卡。
rcc选择crystal。外部时钟
TIM1中选择Channel1的Input Capture direct mode
TIM1中选择Channel2的Input Capture direct mode

TIM3中Clock Source选择Internal Clock
Usart1中MOde选择Asynchronous

其他所有的默认即可。
TIM1用于计数,两个通道同时计数。
TIM3用于定时,并且生成一个脉冲信号
usart用于输出计数结果

Clock configuration选项卡中
时钟我用的25M晶振,系统时钟设为168MHz
APB1 Prescaler 选4,APB2 Prescaler选2

Configuration选项卡中,
usart设置不再讲述,可以去看网站里面的帖子
NVIC按钮打开后,TIM1 Capture Compare interrupt 设为0,2
TIM3 gloable interrupt 设置 0,1
并且以上开启使能
TIM1设置页打开后 counter period (autoreload register-16bits value) 设为65535,up,其他不变,tim1的gpio都设为Pull-up,high
Tim3设置页 prescaler (psc-16 bits value) 为8399
紧接着up,继续9999
最后update event。

好了,设置结束,生成代码,
main.c中的代码:其他的文件没变啊,自己对比添加了哪些吧,懒得一个个写


/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f4xx_hal.h"

/[i] Private variables ---------------------------------------------------------[/i]/
TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim3;

UART_HandleTypeDef huart1;

/[i] USER CODE BEGIN 0 [/i]/
#include "stdio.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /[i] __GNUC__ [/i]/

/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/[i] Place your implementation of fputc here [/i]/
/[i] e.g. write a character to the EVAL_COM1 and Loop until the end of transmission [/i]/
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
uint32_t cont_value1 = 0;
uint32_t cont_value2 = 0;
uint32_t v_value1 = 0;
uint32_t v_value2 = 0;
static void Error_Handler(void);
/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM1_Init(void);
static void MX_TIM3_Init(void);
static void MX_USART1_UART_Init(void);

int main(void)
{

/[i] USER CODE BEGIN 1 [/i]/

/[i] USER CODE END 1 [/i]/

/[i] MCU Configuration----------------------------------------------------------[/i]/

/[i] Reset of all peripherals, Initializes the Flash interface and the Systick. [/i]/
HAL_Init();

/[i] Configure the system clock [/i]/
SystemClock_Config();

/[i] System interrupt init[/i]/
/[i] Sets the priority grouping field [/i]/
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

/[i] Initialize all configured peripherals [/i]/
MX_GPIO_Init();
MX_TIM1_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();

/[i] USER CODE BEGIN 2 [/i]/
HAL_TIM_Base_Start_IT (&htim3 );
if(HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_2) != HAL_OK)
{
/[i] Starting Error [/i]/
Error_Handler();
}
if(HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1) != HAL_OK)
{
/[i] Starting Error [/i]/
Error_Handler();
}
/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{
// HAL_Delay(1000);

// printf ("hello ,my world!");
HAL_Delay(1000);
printf ("%d , %d \r\n",v_value1, v_value2);
cont_value1= 0;cont_value2= 0;

}
/[i] USER CODE END 3 [/i]/

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/[i] TIM1 init function [/i]/
void MX_TIM1_Init(void)
{

TIM_IC_InitTypeDef sConfigIC;
TIM_MasterConfigTypeDef sMasterConfig;

htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 65535;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
HAL_TIM_IC_Init(&htim1);

sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_1);

HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_2);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);

}

/[i] TIM3 init function [/i]/
void MX_TIM3_Init(void)
{

TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;

htim3.Instance = TIM3;
htim3.Init.Prescaler = 8399;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 99;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim3);

sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);

}

/[i] USART1 init function [/i]/
void MX_USART1_UART_Init(void)
{

huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart1);

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/[i] GPIO Ports Clock Enable [/i]/
__GPIOF_CLK_ENABLE();
__GPIOH_CLK_ENABLE();
__GPIOE_CLK_ENABLE();
__GPIOB_CLK_ENABLE();

/[i]Configure GPIO pin : PF6 [/i]/
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

}

/[i] USER CODE BEGIN 4 [/i]/
static void Error_Handler(void)
{
/[i] Turn LED3 on [/i]/
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
while(1)
{
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
v_value1 = cont_value1;v_value2 = cont_value2;
// cont_value = 0;
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6);

}
/**
* @brief Conversion complete callback in non blocking mode
* @param htim : hadc handle
* @retval None
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{

/[i] Get the 1st Input Capture value [/i]/
cont_value1 ++;

}
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{

/[i] Get the 1st Input Capture value [/i]/
cont_value2 ++;

}
}
/[i] USER CODE END 4 [/i]/

#ifdef USE_FULL_ASSERT

/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/[i] USER CODE BEGIN 6 [/i]/
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/[i] USER CODE END 6 [/i]/

}

#endif 查看全部
本次利用了,stm32cubemx生成代码,稍微在main中添加得到
打开cubemx,先设置pinout选项卡。
rcc选择crystal。外部时钟
TIM1中选择Channel1的Input Capture direct mode
TIM1中选择Channel2的Input Capture direct mode

TIM3中Clock Source选择Internal Clock
Usart1中MOde选择Asynchronous

其他所有的默认即可。
TIM1用于计数,两个通道同时计数。
TIM3用于定时,并且生成一个脉冲信号
usart用于输出计数结果

Clock configuration选项卡中
时钟我用的25M晶振,系统时钟设为168MHz
APB1 Prescaler 选4,APB2 Prescaler选2

Configuration选项卡中,
usart设置不再讲述,可以去看网站里面的帖子
NVIC按钮打开后,TIM1 Capture Compare interrupt 设为0,2
TIM3 gloable interrupt 设置 0,1
并且以上开启使能
TIM1设置页打开后 counter period (autoreload register-16bits value) 设为65535,up,其他不变,tim1的gpio都设为Pull-up,high
Tim3设置页 prescaler (psc-16 bits value) 为8399
紧接着up,继续9999
最后update event。

好了,设置结束,生成代码,
main.c中的代码:其他的文件没变啊,自己对比添加了哪些吧,懒得一个个写


/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f4xx_hal.h"

/[i] Private variables ---------------------------------------------------------[/i]/
TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim3;

UART_HandleTypeDef huart1;

/[i] USER CODE BEGIN 0 [/i]/
#include "stdio.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /[i] __GNUC__ [/i]/

/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/[i] Place your implementation of fputc here [/i]/
/[i] e.g. write a character to the EVAL_COM1 and Loop until the end of transmission [/i]/
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
uint32_t cont_value1 = 0;
uint32_t cont_value2 = 0;
uint32_t v_value1 = 0;
uint32_t v_value2 = 0;
static void Error_Handler(void);
/[i] USER CODE END 0 [/i]/

/[i] Private function prototypes -----------------------------------------------[/i]/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM1_Init(void);
static void MX_TIM3_Init(void);
static void MX_USART1_UART_Init(void);

int main(void)
{

/[i] USER CODE BEGIN 1 [/i]/

/[i] USER CODE END 1 [/i]/

/[i] MCU Configuration----------------------------------------------------------[/i]/

/[i] Reset of all peripherals, Initializes the Flash interface and the Systick. [/i]/
HAL_Init();

/[i] Configure the system clock [/i]/
SystemClock_Config();

/[i] System interrupt init[/i]/
/[i] Sets the priority grouping field [/i]/
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

/[i] Initialize all configured peripherals [/i]/
MX_GPIO_Init();
MX_TIM1_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();

/[i] USER CODE BEGIN 2 [/i]/
HAL_TIM_Base_Start_IT (&htim3 );
if(HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_2) != HAL_OK)
{
/[i] Starting Error [/i]/
Error_Handler();
}
if(HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1) != HAL_OK)
{
/[i] Starting Error [/i]/
Error_Handler();
}
/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{
// HAL_Delay(1000);

// printf ("hello ,my world!");
HAL_Delay(1000);
printf ("%d , %d \r\n",v_value1, v_value2);
cont_value1= 0;cont_value2= 0;

}
/[i] USER CODE END 3 [/i]/

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();

__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

}

/[i] TIM1 init function [/i]/
void MX_TIM1_Init(void)
{

TIM_IC_InitTypeDef sConfigIC;
TIM_MasterConfigTypeDef sMasterConfig;

htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 65535;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
HAL_TIM_IC_Init(&htim1);

sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_1);

HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_2);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);

}

/[i] TIM3 init function [/i]/
void MX_TIM3_Init(void)
{

TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;

htim3.Instance = TIM3;
htim3.Init.Prescaler = 8399;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 99;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim3);

sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig);

sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);

}

/[i] USART1 init function [/i]/
void MX_USART1_UART_Init(void)
{

huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart1);

}

/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct;

/[i] GPIO Ports Clock Enable [/i]/
__GPIOF_CLK_ENABLE();
__GPIOH_CLK_ENABLE();
__GPIOE_CLK_ENABLE();
__GPIOB_CLK_ENABLE();

/[i]Configure GPIO pin : PF6 [/i]/
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

}

/[i] USER CODE BEGIN 4 [/i]/
static void Error_Handler(void)
{
/[i] Turn LED3 on [/i]/
HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET );
while(1)
{
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
v_value1 = cont_value1;v_value2 = cont_value2;
// cont_value = 0;
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6);

}
/**
* @brief Conversion complete callback in non blocking mode
* @param htim : hadc handle
* @retval None
*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{

/[i] Get the 1st Input Capture value [/i]/
cont_value1 ++;

}
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{

/[i] Get the 1st Input Capture value [/i]/
cont_value2 ++;

}
}
/[i] USER CODE END 4 [/i]/

#ifdef USE_FULL_ASSERT

/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/[i] USER CODE BEGIN 6 [/i]/
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/[i] USER CODE END 6 [/i]/

}

#endif

stm32cube中文教程:运行中修改TIM定时时间的例子将1s定时运行中改成200ms定时

软件教程admin 发表了文章 • 0 个评论 • 6173 次浏览 • 2014-10-14 00:14 • 来自相关话题

本实验用stm32cubemx生成定时器4的1s定时,然后准备在运行过程中更改定时时间
考虑程序中初始化后定时修改时再次init初始化,应该就可以了。
关于用stm32cube生成定时的方法,请找本论坛文章。
本程序只在原来定时中断中增加了再次初始化代码。
运行正常,测试通过。
代码如下:

其他代码不给出了,只贴出修改了的代码:
在main文件中的定时中断函数中增加:


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
flag++;
HAL_GPIO_TogglePin (GPIOD,GPIO_PIN_14);
if(flag==20)
{
htim4.Init.Period = 1999;
HAL_TIM_Base_Init(&htim4);
}
}

其中flag是计数标示,用来记进入了几次中断,程序中断20次后,修改Period ,然后固化,
之后程序开始以200ms开始闪烁。灯是PD14. 查看全部
本实验用stm32cubemx生成定时器4的1s定时,然后准备在运行过程中更改定时时间
考虑程序中初始化后定时修改时再次init初始化,应该就可以了。
关于用stm32cube生成定时的方法,请找本论坛文章。
本程序只在原来定时中断中增加了再次初始化代码。
运行正常,测试通过。
代码如下:

其他代码不给出了,只贴出修改了的代码:
在main文件中的定时中断函数中增加:


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* NOTE : This function Should not be modified, when the callback is needed,
the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
*/
flag++;
HAL_GPIO_TogglePin (GPIOD,GPIO_PIN_14);
if(flag==20)
{
htim4.Init.Period = 1999;
HAL_TIM_Base_Init(&htim4);
}
}

其中flag是计数标示,用来记进入了几次中断,程序中断20次后,修改Period ,然后固化,
之后程序开始以200ms开始闪烁。灯是PD14.

stm32cube中文教程:DAC输出模拟电压,用12位精度DA最大3.3v,学习笔记

软件教程admin 发表了文章 • 0 个评论 • 10496 次浏览 • 2014-10-14 00:11 • 来自相关话题

用stm32cubemx生成DA输出真对stm32f407的模拟输出电压,很简单
首先,配置时钟,168M,我用的stm32f407discovery板。
这些配置操作我以前提到过,不懂的可以在这个论坛里找找,有图文注释的。
直接点取DAC的通道1,然后去configariton里面配置DAC,其实无需配置,不用改任何东西
生成代码。
打开main文件,找到main函数中初始化后添加:
这个是我自己的例子,你可以适当修改


/[i][size=16]-4- Enable DAC Channel1 [/size]#########################[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[/i]/ [/size][/size][/size][/size][/size][/size][/size]
if(HAL_DAC_Start(&hdac, DAC_CHANNEL_1) != HAL_OK)
{
/[i] Start Error [/i]/
Error_Handler();
}

/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{


HAL_Delay (1);
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6 );
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value );
if(!flag)
{ value ++; if(value==0xfff){ flag=1; }} else { value--;if(!value) flag=0; }
}

代码注释:第一个意思是开启dac的通道1.
while中的意思是:设置DA的值,我用的12位精度,右对齐,值是value,通道DAC_CHANNEL_1
值value从0增加到4095即0xfff,然后从0xfff减小到0,无限循环,哦,上面还有个指示灯,不过
这么高的频率是指示不出来的。是i我调试其他的时候加的,可以无视它。

用示波器 测量PA4管脚(这个就是DA的输出口1),会看到波形类似三角波,电压是从0升到3.3然后再降到0v,ok,结束实验 查看全部
用stm32cubemx生成DA输出真对stm32f407的模拟输出电压,很简单
首先,配置时钟,168M,我用的stm32f407discovery板。
这些配置操作我以前提到过,不懂的可以在这个论坛里找找,有图文注释的。
直接点取DAC的通道1,然后去configariton里面配置DAC,其实无需配置,不用改任何东西
生成代码。
打开main文件,找到main函数中初始化后添加:
这个是我自己的例子,你可以适当修改


/[i][size=16]-4- Enable DAC Channel1 [/size]#########################[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[size=16]#[/i]/ [/size][/size][/size][/size][/size][/size][/size]
if(HAL_DAC_Start(&hdac, DAC_CHANNEL_1) != HAL_OK)
{
/[i] Start Error [/i]/
Error_Handler();
}

/[i] USER CODE END 2 [/i]/

/[i] USER CODE BEGIN 3 [/i]/
/[i] Infinite loop [/i]/
while (1)
{


HAL_Delay (1);
HAL_GPIO_TogglePin (GPIOF,GPIO_PIN_6 );
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value );
if(!flag)
{ value ++; if(value==0xfff){ flag=1; }} else { value--;if(!value) flag=0; }
}

代码注释:第一个意思是开启dac的通道1.
while中的意思是:设置DA的值,我用的12位精度,右对齐,值是value,通道DAC_CHANNEL_1
值value从0增加到4095即0xfff,然后从0xfff减小到0,无限循环,哦,上面还有个指示灯,不过
这么高的频率是指示不出来的。是i我调试其他的时候加的,可以无视它。

用示波器 测量PA4管脚(这个就是DA的输出口1),会看到波形类似三角波,电压是从0升到3.3然后再降到0v,ok,结束实验

巧计APB1(低速外设)APB2(高速外设)上的所对应的外设

经验分享admin 发表了文章 • 0 个评论 • 5480 次浏览 • 2014-10-14 00:01 • 来自相关话题

巧计APB1(低速外设)APB2(高速外设)上的所对应的外设
连接在APB1(低速外设)上的设备有:电源接口、备份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、窗口看门狗、Timer2、Timer3、Timer4。注意USB模块虽然需要一个单独的48MHz时钟信号,但它应该不是供USB模块工作的时钟,而只是提供给串行接口引擎(SIE)使用的时钟。USB模块工作的时钟应该是由APB1提供的。

连接在APB2(高速外设)上的设备有:UART1、SPI1、Timer1、ADC1、ADC2、所有普通IO口(PA~PE)、第二功能IO口。 查看全部
巧计APB1(低速外设)APB2(高速外设)上的所对应的外设
连接在APB1(低速外设)上的设备有:电源接口、备份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、窗口看门狗、Timer2、Timer3、Timer4。注意USB模块虽然需要一个单独的48MHz时钟信号,但它应该不是供USB模块工作的时钟,而只是提供给串行接口引擎(SIE)使用的时钟。USB模块工作的时钟应该是由APB1提供的。

连接在APB2(高速外设)上的设备有:UART1、SPI1、Timer1、ADC1、ADC2、所有普通IO口(PA~PE)、第二功能IO口。

(转载)温控器PID算法的实现(C语言),未实验

新手交流admin 发表了文章 • 0 个评论 • 4176 次浏览 • 2014-10-13 23:42 • 来自相关话题

硬件原理:加热电阻为400,电源为市电,固态继电器控制通断,并提取市电的过零信号,单片机采用mega48,继电器通断最小时间为10ms,通断PWM的周期为100个过零信号.

本程序采用绝对式PID算法,当温度相差很多时,采用P算法(比例算法),当到达设定温度时,采用PID算法,实际实用稳定性还可以,上下波动在0.5度以内.

#include <avr/io.h>
#include "PID.h"
//static PID sPID;
//static PID *sptr=&sPID;
TADD Tadd1;
TADD Tadd2;
void IncPIDInit(PID *sptr)
{
sptr->SumError=0;
sptr->LastError=0;
sptr->PrevError=0;

//sptr->Proportion = 900;
//sptr->Integral=20;
//sptr->Derivative = 2;

//sptr->SetPoint = 0;
}



typedef struct
{
int SetPoint; //设定目标值
int32_t SumError; //误差累计

//int Proportion;
//int Integral; //积分常数
//int Derivative; //微分常数

int LastError; //Error[-1]
int PrevError; //Error[-2]
}PID;
#define PID_Proportion 900 //比例常数
#define PID_Integral 20 //积分常数
#define PID_Derivative 2 //微分常数
#define PWM_T 100
#define MAX_T 80 //加热的最大温度
typedef struct
{
PID spid; //PID控制器
unsigned char pwm_H;//输出
unsigned char EnAdd;//加热使能
int real_T; //实际温度值
unsigned char Taddset[3]; //加热的设定温度
unsigned char set_NO; //加热的档数
unsigned char errorflg;
unsigned char addokflg;
}TADD;

void LocPIDCalc(TADD *sptr)
{
int iError,dError;
int32_t result;
iError = (sptr->spid.SetPoint*4) - (sptr->real_T/4);
//sptr->spid.LastError = iError;
if(iError>-2&&iError<4)
{
sptr->addokflg=1;
sptr->spid.SumError +=iError;
dError = iError-sptr->spid.LastError;
sptr->spid.LastError = iError;
result=(PID_Proportion * iError +
PID_Integral * sptr->spid.SumError +
PID_Derivative * dError)/20;
}
else
{
sptr->spid.SumError =0;
sptr->spid.LastError=0;
if(iError>0)
sptr->addokflg=0;
result=(PID_Proportion * iError)/20;
}
if(result>PWM_T)
result=PWM_T;
else if(result<0)
result=0;
if((sptr->real_T>>4)>MAX_T||sptr->errorflg==0)
result=0;
sptr->pwm_H=(unsigned char) result;
//return (unsigned char) result;
} 查看全部
硬件原理:加热电阻为400,电源为市电,固态继电器控制通断,并提取市电的过零信号,单片机采用mega48,继电器通断最小时间为10ms,通断PWM的周期为100个过零信号.

本程序采用绝对式PID算法,当温度相差很多时,采用P算法(比例算法),当到达设定温度时,采用PID算法,实际实用稳定性还可以,上下波动在0.5度以内.

#include <avr/io.h>
#include "PID.h"
//static PID sPID;
//static PID *sptr=&sPID;
TADD Tadd1;
TADD Tadd2;
void IncPIDInit(PID *sptr)
{
sptr->SumError=0;
sptr->LastError=0;
sptr->PrevError=0;

//sptr->Proportion = 900;
//sptr->Integral=20;
//sptr->Derivative = 2;

//sptr->SetPoint = 0;
}



typedef struct
{
int SetPoint; //设定目标值
int32_t SumError; //误差累计

//int Proportion;
//int Integral; //积分常数
//int Derivative; //微分常数

int LastError; //Error[-1]
int PrevError; //Error[-2]
}PID;
#define PID_Proportion 900 //比例常数
#define PID_Integral 20 //积分常数
#define PID_Derivative 2 //微分常数
#define PWM_T 100
#define MAX_T 80 //加热的最大温度
typedef struct
{
PID spid; //PID控制器
unsigned char pwm_H;//输出
unsigned char EnAdd;//加热使能
int real_T; //实际温度值
unsigned char Taddset[3]; //加热的设定温度
unsigned char set_NO; //加热的档数
unsigned char errorflg;
unsigned char addokflg;
}TADD;

void LocPIDCalc(TADD *sptr)
{
int iError,dError;
int32_t result;
iError = (sptr->spid.SetPoint*4) - (sptr->real_T/4);
//sptr->spid.LastError = iError;
if(iError>-2&&iError<4)
{
sptr->addokflg=1;
sptr->spid.SumError +=iError;
dError = iError-sptr->spid.LastError;
sptr->spid.LastError = iError;
result=(PID_Proportion * iError +
PID_Integral * sptr->spid.SumError +
PID_Derivative * dError)/20;
}
else
{
sptr->spid.SumError =0;
sptr->spid.LastError=0;
if(iError>0)
sptr->addokflg=0;
result=(PID_Proportion * iError)/20;
}
if(result>PWM_T)
result=PWM_T;
else if(result<0)
result=0;
if((sptr->real_T>>4)>MAX_T||sptr->errorflg==0)
result=0;
sptr->pwm_H=(unsigned char) result;
//return (unsigned char) result;
}

stm32中使用DMA,DMA的用法

经验分享admin 发表了文章 • 0 个评论 • 3773 次浏览 • 2014-10-13 23:18 • 来自相关话题

DMA(Direct Memory Access,直接内存存取) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量 中断 负载。否则,CPU 需要从 来源 把每一片段的资料复制到 暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。

DMA 传输将数据从一个地址空间复制到另外一个地址空间。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器 来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。

二.STM32使用DMA

1.DMA的设置:

要配置的有DMA传输通道选择,传输的成员和方向、普通模式还是循环模式等等。


void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
//DMA设置:
//设置DMA源:内存地址&串口数据寄存器地址
//方向:内存-->外设
//每次传输位:8bit
//传输大小DMA_BufferSize=SENDBUFF_SIZE
//地址自增模式:外设地址不增,内存地址自增1
//DMA模式:一次传输,非循环
//优先级:中
DMA_DeInit(DMA1_Channel4);//串口1的DMA传输通道是通道4
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; //DMA访问的数据地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为DMA的目的端
DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//传输数据大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不增加
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址自增1
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//DMA_Mode_Normal(只传送一次), DMA_Mode_Circular (循环传送)
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA传送优先级为中等)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}

注:
1、传输通道:通过查表,串口1的发送对应的是DMA的通道4,所以此处选择通道4.
2、DMA传输方式:
(1) DMA_Mode_Normal,正常模式,当一次DMA数据传输完后,停止DMA传送,对于上例而言,就是DMA_PeripheralDataSize_Byte个字节的传送完成后,就停止传送。
(2) DMA_Mode_Circular
循环模式,当传输完一次后,重新接着传送,永不停息。

2、外设的DMA方式设置
将串口1设置成DMA模式:
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

3、待传输数据的定义和初始化
#define SENDBUFF_SIZE 10240
vu8 SendBuff[SENDBUFF_SIZE];
for(i=0;i<SENDBUFF_SIZE;i++)
{
SendBuff[i] = i+'0';
}
4、开始DMA传输(使能对应的DMA通道)
DMA_Cmd(DMA1_Channel4, ENABLE);

5、DMA传输的完成
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
{
LED_1_REV; //LED改变亮灭
Delay(); //浪费时间
}
当传输完成后,就会跳出上面的死循环。


/******************************************************************************
* 本文件实现串口发送功能(通过重构putchar函数,调用printf;或者USART_SendData()
* 这里是一个用串口实现大量数据传输的例子,使用了DMA模块进行内存到USART的传输
* 每当USART的发送缓冲区空时,USART模块产生一个DMA事件,
* 此时DMA模块响应该事件,自动从预先定义好的发送缓冲区中拿出下一个字节送给USART
* 整个过程无需用户程序干预,用户只需启动DMA传输传输即可
* 在仿真器调试时,可以在数据传输过程中暂停运行,此时DMA模块并没有停止
* 串口依然发送,表明DMA传输是一个独立的过程。
* 同时开启接收中断,在串口中断中将数据存入缓冲区,在main主循环中处理
* 作者:jjldc(九九)
* 代码硬件基于万利199元的EK-STM32F开发板,CPU=STM32F103VBT6
*******************************************************************************/
/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f10x_lib.h"
#include "stdio.h"
/[i] Private typedef -----------------------------------------------------------[/i]/
/[i] Private define ------------------------------------------------------------[/i]/
#define USART1_DR_Base 0x40013804
/[i] Private macro -------------------------------------------------------------[/i]/
/[i] Private variables ---------------------------------------------------------[/i]/
#define SENDBUFF_SIZE 10240
vu8 SendBuff[SENDBUFF_SIZE];
vu8 RecvBuff[10];
vu8 recv_ptr;
/[i] Private function prototypes -----------------------------------------------[/i]/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void DMA_Configuration(void);
void USART1_Configuration(void);
int fputc(int ch, FILE *f);
void Delay(void);
/[i] Private functions ---------------------------------------------------------[/i]/
/*******************************************************************************
* Function Name : main
* Description : Main program.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
int main(void)
{
u16 i;
#ifdef DEBUG
debug();
#endif
recv_ptr = 0;

RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
DMA_Configuration();
USART1_Configuration();

printf("\r\nSystem Start...\r\n");
printf("Initialling SendBuff... \r\n");
for(i=0;i<SENDBUFF_SIZE;i++)
{
SendBuff[i] = i+'0';
}
printf("Initial success!\r\nWaiting for transmission...\r\n");
//发送去数据已经准备好,按下按键即开始传输
while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));

printf("Start DMA transmission!\r\n");

//这里是开始DMA传输前的一些准备工作,将USART1模块设置成DMA方式工作
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
//开始一次DMA传输!
DMA_Cmd(DMA1_Channel4, ENABLE);

//等待DMA传输完成,此时我们来做另外一些事,点灯
//实际应用中,传输数据期间,可以执行另外的任务
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
{
Delay(); //浪费时间
}
//DMA传输结束后,自动关闭了DMA通道,而无需手动关闭
//下面的语句被注释
//DMA_Cmd(DMA1_Channel4, DISABLE);

printf("\r\nDMA transmission successful!\r\n");

/[i] Infinite loop [/i]/
while (1)
{
}
}
/*******************************************************************************
[i] Function Name : 重定义系统putchar函数int fputc(int ch, FILE [/i]f)
* Description : 串口发一个字节
[i] Input : int ch, FILE [/i]f
* Output :
* Return : int ch
* 这个是使用printf的关键
*******************************************************************************/
int fputc(int ch, FILE *f)
{
//USART_SendData(USART1, (u8) ch);
USART1->DR = (u8) ch;

/[i] Loop until the end of transmission [/i]/
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
{
}
return ch;
}
/*******************************************************************************
* Function Name : Delay
* Description : 延时函数
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Delay(void)
{
u32 i;
for(i=0;i<0xF0000;i++);
return;
} 查看全部
DMA(Direct Memory Access,直接内存存取) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量 中断 负载。否则,CPU 需要从 来源 把每一片段的资料复制到 暂存器,然后把它们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。

DMA 传输将数据从一个地址空间复制到另外一个地址空间。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器 来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。

二.STM32使用DMA

1.DMA的设置:

要配置的有DMA传输通道选择,传输的成员和方向、普通模式还是循环模式等等。


void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
//DMA设置:
//设置DMA源:内存地址&串口数据寄存器地址
//方向:内存-->外设
//每次传输位:8bit
//传输大小DMA_BufferSize=SENDBUFF_SIZE
//地址自增模式:外设地址不增,内存地址自增1
//DMA模式:一次传输,非循环
//优先级:中
DMA_DeInit(DMA1_Channel4);//串口1的DMA传输通道是通道4
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; //DMA访问的数据地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为DMA的目的端
DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;//传输数据大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不增加
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址自增1
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//DMA_Mode_Normal(只传送一次), DMA_Mode_Circular (循环传送)
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//(DMA传送优先级为中等)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}

注:
1、传输通道:通过查表,串口1的发送对应的是DMA的通道4,所以此处选择通道4.
2、DMA传输方式:
(1) DMA_Mode_Normal,正常模式,当一次DMA数据传输完后,停止DMA传送,对于上例而言,就是DMA_PeripheralDataSize_Byte个字节的传送完成后,就停止传送。
(2) DMA_Mode_Circular
循环模式,当传输完一次后,重新接着传送,永不停息。

2、外设的DMA方式设置
将串口1设置成DMA模式:
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

3、待传输数据的定义和初始化
#define SENDBUFF_SIZE 10240
vu8 SendBuff[SENDBUFF_SIZE];
for(i=0;i<SENDBUFF_SIZE;i++)
{
SendBuff[i] = i+'0';
}
4、开始DMA传输(使能对应的DMA通道)
DMA_Cmd(DMA1_Channel4, ENABLE);

5、DMA传输的完成
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
{
LED_1_REV; //LED改变亮灭
Delay(); //浪费时间
}
当传输完成后,就会跳出上面的死循环。


/******************************************************************************
* 本文件实现串口发送功能(通过重构putchar函数,调用printf;或者USART_SendData()
* 这里是一个用串口实现大量数据传输的例子,使用了DMA模块进行内存到USART的传输
* 每当USART的发送缓冲区空时,USART模块产生一个DMA事件,
* 此时DMA模块响应该事件,自动从预先定义好的发送缓冲区中拿出下一个字节送给USART
* 整个过程无需用户程序干预,用户只需启动DMA传输传输即可
* 在仿真器调试时,可以在数据传输过程中暂停运行,此时DMA模块并没有停止
* 串口依然发送,表明DMA传输是一个独立的过程。
* 同时开启接收中断,在串口中断中将数据存入缓冲区,在main主循环中处理
* 作者:jjldc(九九)
* 代码硬件基于万利199元的EK-STM32F开发板,CPU=STM32F103VBT6
*******************************************************************************/
/[i] Includes ------------------------------------------------------------------[/i]/
#include "stm32f10x_lib.h"
#include "stdio.h"
/[i] Private typedef -----------------------------------------------------------[/i]/
/[i] Private define ------------------------------------------------------------[/i]/
#define USART1_DR_Base 0x40013804
/[i] Private macro -------------------------------------------------------------[/i]/
/[i] Private variables ---------------------------------------------------------[/i]/
#define SENDBUFF_SIZE 10240
vu8 SendBuff[SENDBUFF_SIZE];
vu8 RecvBuff[10];
vu8 recv_ptr;
/[i] Private function prototypes -----------------------------------------------[/i]/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void DMA_Configuration(void);
void USART1_Configuration(void);
int fputc(int ch, FILE *f);
void Delay(void);
/[i] Private functions ---------------------------------------------------------[/i]/
/*******************************************************************************
* Function Name : main
* Description : Main program.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
int main(void)
{
u16 i;
#ifdef DEBUG
debug();
#endif
recv_ptr = 0;

RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
DMA_Configuration();
USART1_Configuration();

printf("\r\nSystem Start...\r\n");
printf("Initialling SendBuff... \r\n");
for(i=0;i<SENDBUFF_SIZE;i++)
{
SendBuff[i] = i+'0';
}
printf("Initial success!\r\nWaiting for transmission...\r\n");
//发送去数据已经准备好,按下按键即开始传输
while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));

printf("Start DMA transmission!\r\n");

//这里是开始DMA传输前的一些准备工作,将USART1模块设置成DMA方式工作
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
//开始一次DMA传输!
DMA_Cmd(DMA1_Channel4, ENABLE);

//等待DMA传输完成,此时我们来做另外一些事,点灯
//实际应用中,传输数据期间,可以执行另外的任务
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
{
Delay(); //浪费时间
}
//DMA传输结束后,自动关闭了DMA通道,而无需手动关闭
//下面的语句被注释
//DMA_Cmd(DMA1_Channel4, DISABLE);

printf("\r\nDMA transmission successful!\r\n");

/[i] Infinite loop [/i]/
while (1)
{
}
}
/*******************************************************************************
[i] Function Name : 重定义系统putchar函数int fputc(int ch, FILE [/i]f)
* Description : 串口发一个字节
[i] Input : int ch, FILE [/i]f
* Output :
* Return : int ch
* 这个是使用printf的关键
*******************************************************************************/
int fputc(int ch, FILE *f)
{
//USART_SendData(USART1, (u8) ch);
USART1->DR = (u8) ch;

/[i] Loop until the end of transmission [/i]/
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
{
}
return ch;
}
/*******************************************************************************
* Function Name : Delay
* Description : 延时函数
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Delay(void)
{
u32 i;
for(i=0;i<0xF0000;i++);
return;
}

转载:调试硬件I2C心得,关于Stm8的仿真测试

经验分享admin 发表了文章 • 0 个评论 • 2193 次浏览 • 2014-10-13 23:10 • 来自相关话题

Stm8不需要专门配置GPIO口,执行初始化就可以啦!有些stm8需要打开EEPROM设置I2C(看官方文档)。

Stm8主要靠SR1和SR3状态寄存器判断I2C的情况(while(!XXXXX)就是出自这里),多半大家调不通!就是卡在这里(需要注意的是 寄存器有些位,只要读寄存器就可以清除,在仿真的时候,最好不要打开寄存器页面)。这里分软故障和硬故障:

首先是硬故障: 一般是stm8芯片IO口坏啦,有些时候stm8能够写程序而且IO别的功能都是好的,单单是I2C用不起!还有就是IO上拉电压不够!我就遇到这样的问题,我IO 加上逻辑分析仪后就可以调通,不加就通不了。这个也搞啦我很久。

软故障: 一般主要是设置CR1和CR2问题,只要按照我的参考程序设置就可以!

我详细的讲讲,寄存器I2c_CR2 应答使能位(位2)ack。首先是理解:官方文档上面说的是ack应答使能,对是使能!很多人包括我自己 开始都认为是发送ack,导致每次stm8收到数据后,我们都手动在每次收到字节后加I2C_AcknowledgeConfig(I2C_ACK_CURR)无任何意义,因为在接收模式下,收到完整字节后,自动发送ack(提前是CR2 ack位使能,不需要专门CR2 ack位置1) ,都是软件虚拟I2C用多啦!想当然啦!
还有就是使用这个ack!设置ACK都必须在接收字节前,也就是说为个在收到最后一个字节后产生一个NACK 脉冲,在读倒数第二个数据字节之后,必须清除ack位(ack=0)!设置ack同理! 还有需要 主要的地方 如果设置 ack=0; 下次需要重新产生ack的时候!需要手动置位ack!记住在开始接收之前!如果你只有一个字节正确,后面全部是0xFF...可能就是这个问题(切记!切记!很多例子都没有加上这句,包括风驰 的例子!! 不过 他没有加循环! 如果他再循环一次就会出现问题。)

随便说说仿真调试!在调试过程中,最好不要打开I2C寄存器看!因为对寄存器的读,也会造成寄存器有些位重置!直接按Go,然后暂停。进去程序看卡在那里啦。

操作库和寄存器编写程序,其实没有分别!不过为啦更好的理解,我在这里是操作寄存器!网上有人说加入中断会对I2C产生影响,我这里没有加中断。希望有后来人补全!反正我这几天运行没有发现问题! 查看全部
Stm8不需要专门配置GPIO口,执行初始化就可以啦!有些stm8需要打开EEPROM设置I2C(看官方文档)。

Stm8主要靠SR1和SR3状态寄存器判断I2C的情况(while(!XXXXX)就是出自这里),多半大家调不通!就是卡在这里(需要注意的是 寄存器有些位,只要读寄存器就可以清除,在仿真的时候,最好不要打开寄存器页面)。这里分软故障和硬故障:

首先是硬故障: 一般是stm8芯片IO口坏啦,有些时候stm8能够写程序而且IO别的功能都是好的,单单是I2C用不起!还有就是IO上拉电压不够!我就遇到这样的问题,我IO 加上逻辑分析仪后就可以调通,不加就通不了。这个也搞啦我很久。

软故障: 一般主要是设置CR1和CR2问题,只要按照我的参考程序设置就可以!

我详细的讲讲,寄存器I2c_CR2 应答使能位(位2)ack。首先是理解:官方文档上面说的是ack应答使能,对是使能!很多人包括我自己 开始都认为是发送ack,导致每次stm8收到数据后,我们都手动在每次收到字节后加I2C_AcknowledgeConfig(I2C_ACK_CURR)无任何意义,因为在接收模式下,收到完整字节后,自动发送ack(提前是CR2 ack位使能,不需要专门CR2 ack位置1) ,都是软件虚拟I2C用多啦!想当然啦!
还有就是使用这个ack!设置ACK都必须在接收字节前,也就是说为个在收到最后一个字节后产生一个NACK 脉冲,在读倒数第二个数据字节之后,必须清除ack位(ack=0)!设置ack同理! 还有需要 主要的地方 如果设置 ack=0; 下次需要重新产生ack的时候!需要手动置位ack!记住在开始接收之前!如果你只有一个字节正确,后面全部是0xFF...可能就是这个问题(切记!切记!很多例子都没有加上这句,包括风驰 的例子!! 不过 他没有加循环! 如果他再循环一次就会出现问题。)

随便说说仿真调试!在调试过程中,最好不要打开I2C寄存器看!因为对寄存器的读,也会造成寄存器有些位重置!直接按Go,然后暂停。进去程序看卡在那里啦。

操作库和寄存器编写程序,其实没有分别!不过为啦更好的理解,我在这里是操作寄存器!网上有人说加入中断会对I2C产生影响,我这里没有加中断。希望有后来人补全!反正我这几天运行没有发现问题!