warning: #550-D: variable "xFrameReceived" was set but never used

回复

myuse 发起了问题 • 1 人关注 • 0 个回复 • 2095 次浏览 • 2016-05-27 22:15 • 来自相关话题

分享一个多路ADC循环扫描+DMA传输的例子

回复

DengQilong 发起了问题 • 1 人关注 • 0 个回复 • 2512 次浏览 • 2016-03-19 12:24 • 来自相关话题

(转)与DMA的那些事 , DMA在外设与存储器之间的应用举例!

admin 发表了文章 • 0 个评论 • 3345 次浏览 • 2016-03-02 09:16 • 来自相关话题

参考手册上是这样介绍DMA的:用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何 CPU 操作的情况下通过 DMA 快速移动数据。这样节省的 CPU 资源可供其它操作使用。从上面我们可以看到DMA就好比是个“包邮的快递”一样,可以不收钱(不占用CPU)帮我们送快递(传递数据),有这等便宜岂能放过,我们必须要“用用用”!
1、DMA写SD卡
我最开始使用DMA是写SD卡,因为STM32的SPI在连续传递数据时字节和字节之间有很大的时间间隔,这导致了写一个扇区需要很长的时间,经过很多测试发现字节之间的间隔没法很好的被优化掉,所以就考虑用DMA写SD卡了。使用DMA写SD卡时只需设置好要写的数据,然后使能DMA传输完成中断,在中断中判断写数据是否成功。
如果使用常规的SPI写SD没有问题,那么修改为SPI的DMA模式写SD就卡就比较简单了。只需要修改下面几个函数即可。
1) 在写512字节时使用DMA传输





2) 在中断函数中进行判断即可void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
uint8_t t,s;
//扇区写完后发送校验字节
SPI2_ReadWriteByte(0xFF);
SPI2_ReadWriteByte(0xFF);
for(s = 0;s < 255;s++)
{
//接收响应
t = SPI2_ReadWriteByte(0xFF);
if((t&0x1F)==0x05)
{
SD_DMA_Write_Status = Status_OK;
break;
}
}
if(s == 0xff)
{
s = s;
}
SD_DisSelect();

}
2、DMA传输多通道ADC采集数据
这个测试使用NUCLEO-STM32F410RB,我们先初始化4个通道的ADC输出,然后用DMA将转换的数据传到数组中。
  4个通道配置如下:










然后在main函数中开始adc的转换:#include "main.h"

__IO uint16_t uhADCxConvertedValue[4];
int main(void)
{
HAL_Init();
SystemClock_Config();
LED_Init();
USART2_Init();
ADC1_Init();
ADC1_Config();
HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)&uhADCxConvertedValue, 4);

while(1)
{

}
}



首先悬空4个输入引脚,从转换结果可以看到ADC的值为随机值,这也说明了可以使用悬空ADC引脚的方法来产生随机数是可行的。










将其中的2个通道接地,可以看到ADC的值接近0





3、使用DMA和串口空闲中断接收不定长数据
这个测试也使用NUCLEO-STM32F410RB。串口在接收数据时使用空闲中断和DMA接收不定长的数据,在发送时使用DMA发送。使用这个方法能够很方便的接收不定长的数据,但是也有一些限制,实际使用中如果出现问题要根据需要优化。
需要注意的是使用HAL库要自己写个回调函数如下:





在main中我们将PC端发送的数据返回到PC端:#include "main.h"

int main(void)
{
HAL_Init();
SystemClock_Config();
LED_Init();
USART2_Init();
while(1)
{
if(U1_Rxlen)
{
HAL_UART_Transmit_DMA(&UARTHandle,aU3RxBuff,U1_Rxlen);
U1_Rxlen = 0;
}
}
}



发送不同长度的数据,可以看到都能够正确接收:




上面只是DMA的几个最简单的使用,因为比较常用而且简单,所以并没有详细的叙述,具体可以参考代码。测试代码是使用hal写的,明白了原理很容易转换为标准库。DMA在其他的外设也有很多可以使用的场合,合理使用DMA能起到事半功倍的效果
 
文中所提到的相关代码,在本站百度网盘中[与DMA的那些事代码]中可下载
 
原帖地址:http://www.stmcu.org/module/forum/thread-605178-1-1.html
感谢creep分享 查看全部
参考手册上是这样介绍DMA的:用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何 CPU 操作的情况下通过 DMA 快速移动数据。这样节省的 CPU 资源可供其它操作使用。从上面我们可以看到DMA就好比是个“包邮的快递”一样,可以不收钱(不占用CPU)帮我们送快递(传递数据),有这等便宜岂能放过,我们必须要“用用用”!
1、DMA写SD卡
我最开始使用DMA是写SD卡,因为STM32的SPI在连续传递数据时字节和字节之间有很大的时间间隔,这导致了写一个扇区需要很长的时间,经过很多测试发现字节之间的间隔没法很好的被优化掉,所以就考虑用DMA写SD卡了。使用DMA写SD卡时只需设置好要写的数据,然后使能DMA传输完成中断,在中断中判断写数据是否成功。
如果使用常规的SPI写SD没有问题,那么修改为SPI的DMA模式写SD就卡就比较简单了。只需要修改下面几个函数即可。
1) 在写512字节时使用DMA传输

QQ图片20160302090653.jpg

2) 在中断函数中进行判断即可
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
uint8_t t,s;
//扇区写完后发送校验字节
SPI2_ReadWriteByte(0xFF);
SPI2_ReadWriteByte(0xFF);
for(s = 0;s < 255;s++)
{
//接收响应
t = SPI2_ReadWriteByte(0xFF);
if((t&0x1F)==0x05)
{
SD_DMA_Write_Status = Status_OK;
break;
}
}
if(s == 0xff)
{
s = s;
}
SD_DisSelect();

}

2、DMA传输多通道ADC采集数据
这个测试使用NUCLEO-STM32F410RB,我们先初始化4个通道的ADC输出,然后用DMA将转换的数据传到数组中。
  4个通道配置如下:

212624litd2fmbbyw2u6hu.jpg


212624ftpntnwmhehbmpei.jpg

然后在main函数中开始adc的转换:
#include "main.h"

__IO uint16_t uhADCxConvertedValue[4];
int main(void)
{
HAL_Init();
SystemClock_Config();
LED_Init();
USART2_Init();
ADC1_Init();
ADC1_Config();
HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)&uhADCxConvertedValue, 4);

while(1)
{

}
}



首先悬空4个输入引脚,从转换结果可以看到ADC的值为随机值,这也说明了可以使用悬空ADC引脚的方法来产生随机数是可行的。

212625iz9q94xo44999g0v.jpg


212625ywppmbvs5sz9x5w8.jpg

将其中的2个通道接地,可以看到ADC的值接近0
213833qxtfjfn9ln44pxxn.png


3、使用DMA和串口空闲中断接收不定长数据
这个测试也使用NUCLEO-STM32F410RB。串口在接收数据时使用空闲中断和DMA接收不定长的数据,在发送时使用DMA发送。使用这个方法能够很方便的接收不定长的数据,但是也有一些限制,实际使用中如果出现问题要根据需要优化。
需要注意的是使用HAL库要自己写个回调函数如下:

214207ajqgjgxabaq4dge1.jpg

在main中我们将PC端发送的数据返回到PC端:
#include "main.h"

int main(void)
{
HAL_Init();
SystemClock_Config();
LED_Init();
USART2_Init();
while(1)
{
if(U1_Rxlen)
{
HAL_UART_Transmit_DMA(&UARTHandle,aU3RxBuff,U1_Rxlen);
U1_Rxlen = 0;
}
}
}



发送不同长度的数据,可以看到都能够正确接收:
214358hv9zr89q8qmkrg5r.jpg

上面只是DMA的几个最简单的使用,因为比较常用而且简单,所以并没有详细的叙述,具体可以参考代码。测试代码是使用hal写的,明白了原理很容易转换为标准库。DMA在其他的外设也有很多可以使用的场合,合理使用DMA能起到事半功倍的效果
 
文中所提到的相关代码,在本站百度网盘中[与DMA的那些事代码]中可下载
 
原帖地址:http://www.stmcu.org/module/forum/thread-605178-1-1.html
感谢creep分享

(转)使用片内的CCMRAM缩短代码执行时间【STM32F303开发】

admin 发表了文章 • 0 个评论 • 2057 次浏览 • 2016-01-06 14:19 • 来自相关话题

之前使用F4的时候就发现片内个CCMRAM区域可以用于内核直接读取,进而缩短减小等待时间。拿到F3后发现里面也有个CCMRAM,功能比F4的还强大,所以就准备测试下。
现在使用的F303RE内部有个16K的CCM直接和数据总线和指令总线相连,也就是说CPU能以最大的系统时钟和最小的等待时间从CCM中读取数据或者代码,这个CCM区域只能由CPU访问,DMA不能从CCM中读取数据。官方文档说明了使用CCM的一些优势:比如将频繁读取的数据放到CCM,将中断函数放到CCM,这都能加快程序的执行速度。
![请输入图片名称](http://www.stmcu.org/module/fo ... 6f.jpg)
使用CCM的设置比较简单,首先编辑分散加载文件,将CCM区域加入到里面
![请输入图片名称](http://www.stmcu.org/module/fo ... ac.jpg)
下面手动编辑修改SCT文件,添加CCM部分到sct
![请输入图片名称](http://www.stmcu.org/module/fo ... rm.jpg)
下面将需要放到CCM内存的变量,数组,函数等的前面添加下面的关键字即可

{{{
__attribute__((section("ccmram")))
}}}
为了使用使用方便我们将上面的关键字定义为下面的宏

{{{
#define CCMRAM __attribute__((section("ccmram")))
}}}
比如我将一个数组放到CCM中,将CCMRAM放在定义的数组即可,

{{{
CCMRAM const char buff[20] = "\r\nHi,i am creep!";
}}}
将一个函数放到CCM

{{{

CCMRAM void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}

}}}
重新编译后,你就可以从MAP文件中看到相应的数组和函数被放到0x1000000开始的CCM区域,或者debug也能看到相应的地址,我们将数组和函数的地址发送到串口,可看到的确是在0x10000000之后。
![请输入图片名称](http://www.stmcu.org/module/fo ... mi.jpg)
刚才说了,F4系列也有个CCM的区域,测试完F3,我又测试下F4,比较悲剧的是只要把函数定义在CCM中程序就会Fault,只定义数组却没有问题,查看map文件,函数地址的确是被分配到了CCM,郁闷了几分钟,重新找到F429的RM,看下了总线矩阵图才发现原因。。。

>>http://www.stmcu.org/module/fo ... .html 查看全部
之前使用F4的时候就发现片内个CCMRAM区域可以用于内核直接读取,进而缩短减小等待时间。拿到F3后发现里面也有个CCMRAM,功能比F4的还强大,所以就准备测试下。
现在使用的F303RE内部有个16K的CCM直接和数据总线和指令总线相连,也就是说CPU能以最大的系统时钟和最小的等待时间从CCM中读取数据或者代码,这个CCM区域只能由CPU访问,DMA不能从CCM中读取数据。官方文档说明了使用CCM的一些优势:比如将频繁读取的数据放到CCM,将中断函数放到CCM,这都能加快程序的执行速度。
![请输入图片名称](http://www.stmcu.org/module/fo ... 6f.jpg)
使用CCM的设置比较简单,首先编辑分散加载文件,将CCM区域加入到里面
![请输入图片名称](http://www.stmcu.org/module/fo ... ac.jpg)
下面手动编辑修改SCT文件,添加CCM部分到sct
![请输入图片名称](http://www.stmcu.org/module/fo ... rm.jpg)
下面将需要放到CCM内存的变量,数组,函数等的前面添加下面的关键字即可

{{{
__attribute__((section("ccmram")))
}}}
为了使用使用方便我们将上面的关键字定义为下面的宏

{{{
#define CCMRAM __attribute__((section("ccmram")))
}}}
比如我将一个数组放到CCM中,将CCMRAM放在定义的数组即可,

{{{
CCMRAM const char buff[20] = "\r\nHi,i am creep!";
}}}
将一个函数放到CCM

{{{

CCMRAM void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}

}}}
重新编译后,你就可以从MAP文件中看到相应的数组和函数被放到0x1000000开始的CCM区域,或者debug也能看到相应的地址,我们将数组和函数的地址发送到串口,可看到的确是在0x10000000之后。
![请输入图片名称](http://www.stmcu.org/module/fo ... mi.jpg)
刚才说了,F4系列也有个CCM的区域,测试完F3,我又测试下F4,比较悲剧的是只要把函数定义在CCM中程序就会Fault,只定义数组却没有问题,查看map文件,函数地址的确是被分配到了CCM,郁闷了几分钟,重新找到F429的RM,看下了总线矩阵图才发现原因。。。

>>http://www.stmcu.org/module/fo ... .html

(转)分析和理解stm32的IAP功能怎么实现的?

回复

admin 发起了问题 • 4 人关注 • 0 个回复 • 4579 次浏览 • 2015-07-28 17:06 • 来自相关话题

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

admin 发表了文章 • 0 个评论 • 6525 次浏览 • 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 个评论 • 3918 次浏览 • 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
插入串口线,设备管理器里面删除掉此时的端口,或者修改为其他端口,若是删除的,则再次插入后自动变更.

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

admin 发表了文章 • 0 个评论 • 4335 次浏览 • 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口。

stm32中使用DMA,DMA的用法

admin 发表了文章 • 0 个评论 • 3263 次浏览 • 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;
}

关于stm32f4的I2S全双工模式程序(转载)

admin 发表了文章 • 0 个评论 • 6134 次浏览 • 2014-10-13 23:12 • 来自相关话题

以下:GPIO Init


GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 |GPIO_Pin_14 | GPIO_Pin_15;//WS CK SD
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_I2S2ext);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //MCLK
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_SPI2);

以下I2S Init:


I2S_InitTypeDef I2S_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
SPI_I2S_DeInit(SPI2);

I2S_StructInit(&I2S_InitStructure);
I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_8k;;
I2S_InitStructure.I2S_Standard = I2S_Standard_MSB;
I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
I2S_Init(SPI2, &I2S_InitStructure);

I2S_FullDuplexConfig(I2S2ext, &I2S_InitStructure);
I2S_Cmd(SPI2, DISABLE);

I2S_Cmd(I2S2ext, ENABLE);



for(i=0;i<200;i++)
{
while (SPI_I2S_GetFlagStatus(I2S2ext, SPI_FLAG_RXNE) == RESET);
soundbuf1[i] = SPI_I2S_ReceiveData(I2S2ext);
} 查看全部
以下:GPIO Init


GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 |GPIO_Pin_14 | GPIO_Pin_15;//WS CK SD
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_I2S2ext);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //MCLK
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_SPI2);

以下I2S Init:


I2S_InitTypeDef I2S_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
SPI_I2S_DeInit(SPI2);

I2S_StructInit(&I2S_InitStructure);
I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_8k;;
I2S_InitStructure.I2S_Standard = I2S_Standard_MSB;
I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
I2S_Init(SPI2, &I2S_InitStructure);

I2S_FullDuplexConfig(I2S2ext, &I2S_InitStructure);
I2S_Cmd(SPI2, DISABLE);

I2S_Cmd(I2S2ext, ENABLE);



for(i=0;i<200;i++)
{
while (SPI_I2S_GetFlagStatus(I2S2ext, SPI_FLAG_RXNE) == RESET);
soundbuf1[i] = SPI_I2S_ReceiveData(I2S2ext);
}

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

admin 发表了文章 • 0 个评论 • 2000 次浏览 • 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产生影响,我这里没有加中断。希望有后来人补全!反正我这几天运行没有发现问题!