STM32-custom usb

2023-11-18

如何建立一个自定义的HID工程呢?下面就来讲讲。
首先先介绍下工程的架构,工程的总体架构下图所示,按照下图架构建工程:
分析下工程布局,首先是APP,这个组里存放着主文件mian.c,管理所有中断服务程序stm3210x_it.c,及其管理外设库头文件的stm32f10x_conf.h。BSP这个组里存放着BSP.c,外设的洗衣初始化都在这个函数中定义,比如说串口的配置,LED灯的配置,系统时钟的配置,各类NVIC的中断配置。在这个文件中,会定义一个BSP_Init()函数,所有配置的都在这个函数中调用,例如:

void BSP_Init(void) { RCC_Configuration(); Set_USBClock(); USB_Init(); USART1_Configuration(115200); LED_Configuration(); NVIC_Configuration(); USB_Interrupts_Config(); }

而这个BSP_Init()函数在main中调用,这样就使主函数简洁漂亮了。至于CMSIS这个组则是关于Cotex-M3内核的相关文件看,如core_cm3.c和system_stm32f10x.c。StartUp这个组放置系统的启动文件,不同系类的处理器使用不同的启动文件,这里有必要了解:

- startup_stm32f10x_ld_vl.s: for STM32 Low density Value line devices - startup_stm32f10x_ld.s: for STM32 Low density devices - startup_stm32f10x_md_vl.s: for STM32 Medium density Value line devices - startup_stm32f10x_md.s: for STM32 Medium density devices - startup_stm32f10x_hd.s: for STM32 High density devices - startup_stm32f10x_xl.s: for STM32 XL density devices - startup_stm32f10x_cl.s: for STM32 Connectivity line devices cl:互联型产品,stm32f105/107系列 vl:超值型产品,stm32f100系列 xl:超高密度产品,stm32f101/103系列 ld:低密度产品,FLASH小于64K md:中等密度产品,FLASH=64 or 128 hd:高密度产品,FLASH大于128

我的这个工程选择高密度型的: startup_stm32f10x_hd.s。USB_User文件组放着USB控制与应用相关的文件,在之前的文章每个文件都详细介绍过。接着是USB-FS-Device_Driver这个组放着USB的驱动,在之前的文章页已经讲述过。最后一个组是STM32F10x_StdPeriph_Driver,它里面存放着外设库文件的驱动代码,很多人为了省事,会把所有的C文件都添加进来,我不建议这么做,还是根据需要添加对应的文件,就拿我们的这个CustomHID工程,我们用到了引脚GPIO、时钟的配置,串口的配置,所以只要添加这几个对应的C库文件就可以了。
  上面的各个文件大部分可以网上下载的。
接下去就讲述如何实现CustomHID功能的。
首先,最重要的文件当然是usb_desc.c这个文件了。这个文件存放着各种描述符,比如说设备描述符、配置描述符等,下面就一一介绍。
设备描述符符的定义如下:

/* USB标准设备描述符*/ const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] = { 0x12, /*bLength:长度,设备描述符的长度为18字节*/ USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType:类型,设备描述符的编号是0x01*/ 0x00, /*bcdUSB:所使用的USB版本为2.0*/ 0x02, 0x00, /*bDeviceClass:设备所使用的类代码*/ 0x00, /*bDeviceSubClass:设备所使用的子类代码*/ 0x00, /*bDeviceProtocol:设备所使用的协议*/ 0x40, /*bMaxPacketSize:最大包长度为64字节*/ 0x34, /*idVendor:厂商ID为0x1234*/ 0x12, 0x10, /*idProduct:产品ID为0x1010*/ 0x10, 0x00, /*bcdDevice:设备的版本号为2.00*/ 0x02, 1, /*iManufacturer:厂商字符串的索引*/ 2, /*iProduct:产品字符串的索引*/ 3, /*iSerialNumber:设备的序列号字符串索引*/ 0x01 /*bNumConfiguration:设备有1种配置*/ }; /* CustomHID设备描述符 */

设备描述符的数组的长度一般为9个字节,该描述符定义了USB协议代号、厂商ID(VID),产品ID(PID)、设备的版本号、以及厂商产品序列号描述符的索引。在USB枚举阶段,USB设备需要通过端口0向USB主机发送设备描述符。
配置描述符集合里有着丰富的USB设备的信息,如用了几个接口,用了几个端点,USB设备做什么用等。代码如下:

/* USB配置描述符集合(配置、接口、端点、类、厂商)(Configuration, Interface, Endpoint, Class, Vendor */ const uint8_t CustomHID_ConfigDescriptor[CUSTOMHID_SIZ_CONFIG_DESC] = { 0x09, /*bLength:长度,设备字符串的长度为9字节*/ USB_CONFIGURATION_DESCRIPTOR_TYPE, /*bDescriptorType:类型,配置描述符的类型编号为0x2*/ CUSTOMHID_SIZ_CONFIG_DESC, /*wTotalLength:配置描述符的总长度为41字节*/ 0x00, 0x01, /*bNumInterfaces:配置所支持的接口数量1个*/ 0x01, /*bConfigurationValue:该配置的值*/ 0x00, /*iConfiguration:该配置的字符串的索引值,该值为0表示没有字符串*/ 0xC0, /* bmAttributes:设备的一些特性,0xc0表示自供电,不支持远程唤醒 D7:保留必须为1,D6:是否自供电,D5:是否支持远程唤醒,D4~D0:保留设置为0*/ // 0x32, /*从总线上获得的最大电流为100mA */ 0x96, /*MaxPower:设备需要从总线上获取多少电流,单位为2mA,0x96表示300mA*/ /************** HID接口描述符****************/ 0x09, /*bLength:长度,接口描述符的长度为9字节 */ USB_INTERFACE_DESCRIPTOR_TYPE,/* bDescriptorType:接口描述符的类型为0x4 */ 0x00, /*bInterfaceNumber:该接口的编号*/ 0x00, /*bAlternateSetting:该接口的备用编号 */ 0x02, /*bNumEndpoints:该接口所使用的端点数*/ 0x03, /*bInterfaceClass该接口所使用的类为HID*/ 0x00, /*bInterfaceSubClass:该接口所用的子类 1=BOOT, 0=no boot */ 0x00, /*nInterfaceProtocol :该接口使用的协议0=none, 1=keyboard, 2=mouse */ 0, /*iInterface: 该接口字符串的索引 */ /*****************HID描述符 ********************/ 0x09, /*bLength: HID描述符的长度为9字节 */ HID_DESCRIPTOR_TYPE, /* bDescriptorType: HID的描述符类型为0x21 */ 0x10, /*bcdHID: HID协议的版本为1.1 */ 0x01, 0x00, /*bCountryCode: 国家代号 */ 0x01, /*bNumDescriptors: 下级描述符的数量*/ 0x22, /*bDescriptorType:下级描述符的类型*/ CUSTOMHID_SIZ_REPORT_DESC,/* wItemLength: 下一集描述符的长度*/ 0x00, /********************输入端点描述符******************/ 0x07, /* bLength: 端点描述符的长度为7字节*/ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: 端点描述符的类型为0x21*/ 0x82, /* bEndpointAddress: 该端点(输入)的地址,D7:0(OUT),1(IN),D6~D4:保留,D3~D0:端点号*/ 0x03, /* bmAttributes: 端点的属性为为中断端点. D0~D1表示传输类型:0(控制传输),1(等时传输),2(批量传输),3(中断传输) 非等时传输端点:D2~D7:保留为0 等时传输端点: D2~D3表示同步的类型:0(无同步),1(异步),2(适配),3(同步) D4~D5表示用途:0(数据端点),1(反馈端点),2(暗含反馈的数据端点),3(保留),D6~D7:保留,*/ 0x40, /* wMaxPacketSize: 该端点支持的最大包长度为64字节*/ 0x00, 0x02, /* bInterval: 轮询间隔(2 ms) */ /********************输出端点描述符******************/ 0x07, /* 端点描述符的长度为7字节 */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: 端点描述符的类型为0x21*/ 0x01, /* bEndpointAddress: 该端点(输出)的地址,D7:0(OUT),1(IN),D6~D4:保留,D3~D0:端点号*/ 0x03, /* bmAttributes: 端点的属性为为中断端点 */ 0x40, /* wMaxPacketSize: 该端点支持的最大包长度为64字节 */ 0x00, 0x02, /* bInterval: 轮询间隔(2 ms) */ };

从上面的代码中可以看出,USB设备使用了1个接口、两个端点:一个中断传输输入端点,端点号为2;一个中断传输的输出端点,端点号为1、每个端点能通讯的最大数据包长度为64字节、USB的功能自定义等。配置描述符是在USB主机发送GET_CONFIGURATION请求时,USB设备发送的。
还有一个很重要的当然报告描述符了:

/* HID的报告描述符*/ const uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] = { /*short Item D7~D4:bTag;D3~D2:bType;D1~D0:bSize **bTag —主条目 1000:输入(Input) 1001:输出(Output) 1011:特性(Feature) 1010:集合(Collection) 1100:关集合(End Collection) ** 全局条目 0000:用途页(Usage Page) 0001:逻辑最小值(Logical Minimum) 0010:逻辑最大值(Logical Maximum) 0011:物理最小值(Physical Minimum) ** 0100:物理最大值(Physical Maximum) 0101:单元指数(Unit Exponet) 0110:单元(Unit) 0111:数据域大小(Report Size) ** 1000:报告ID(Report ID) 1001:数据域数量(Report Count) 1010:压栈(Push) 1011:出栈(Pop) 1100~1111:保留(Reserved) ** 局部条目 0000:用途(Usage) 0001:用途最小值(Usage Minimum) 0010:用途最大值(Usage Maximum) 0011:标识符索引(Designator Index) ** 0100:标识符最小值(Designator Minimum) 0101:标识符最大值(Designator Maximum) 0111:字符串索引(String Index) 1000:字符串最小值(String Minimum) ** 1001:字符串最大值(String Maximum) 1010:分隔符(Delimiter) 其他:保留(Reserved) **bType—00:主条目(main) 01:全局条目(globle) 10:局部条目(local) 11:保留(reserved) **bSize—00:0字节 01:1字节 10:2字节 11:4字节*/ //0x05:0000 01 01 这是个全局条目,用途页为ST页 0x05, 0x8c, /* USAGE_PAGE (ST Page) */ //0x09:0000 10 01 这是个局部变量,用途为Demo Kit 0x09, 0x01, /* USAGE (Demo Kit) */ //0xa1:1010 00 01 这是一个主条目,集合为应用集合 0xa1, 0x01, /* COLLECTION (Application) */ /* 输入报告*/ //0x09:0000 10 01 这是个局部条目,用途为厂商ID 0x09,0x03, // USAGE ID - Vendor defined //0x15:0001 01 01 这是个全局条目,逻辑最小值为0 0x15,0x00, // LOGICAL_MINIMUM (0) //0x26:0010 01 10 这是个全局条目,逻辑最大值为255 0x26,0x00, 0xFF, // LOGICAL_MAXIMUM (255) //0x75:0111 01 01 这是个全局条目,报告大小为8位 0x75,0x08, // REPORT_SIZE (8bit) //0x95:1001 01 01 这是个全局条目,报告数量为64 0x95,0x40, // REPORT_COUNT (64Byte) //0x81:1000 00 01 这是个主条目,做输入,Data表示这些数据可变,Var表示这些徐居于是独立的变量,Abs表示绝对值 0x81,0x02, // INPUT (Data,Var,Abs) /*输出报告*/ //0x09:0000 10 01 这是个局部条目,用途为厂商ID 0x09,0x04, // USAGE ID - Vendor defined //0x15:0001 01 01 这是个全局条目,逻辑最小值为0 0x15,0x00, // LOGICAL_MINIMUM (0) //0x26:0010 01 10 这是个全局条目,逻辑最大值为255 0x26,0x00,0xFF, // LOGICAL_MAXIMUM (255) //0x75:0111 01 01 这是个全局条目,报告大小为8位 0x75,0x08, // REPORT_SIZE (8bit) //0x95:1001 01 01 这是个全局条目,报告数量为64 0x95,0x40, // REPORT_COUNT (64Byte) //0x91:1001 00 01 这是个全局条目,做输出,Data表示这些数据可变,Var表示这些徐居于是独立的变量,Abs表示绝对值 0x91,0x02, // OUTPUT (Data,Var,Abs) 0xc0 /* END_COLLECTION */ };

关于配置描述符也是至关重要的,它规定了USB通讯的长度,具体格式。据上面的报告描述符说:定义了64*8bit的数据域作为输入,属性是Data、Var、Abs,也就是说USB设备想USB主机每次发送64字节的数据包,每个数据的值(0~255之间)可以用户自定义;还定义了64*8bit的数据域作为输出,属性是Data、Var、Abs,也就是说USB主机箱USB设备每次发送64字节的数据包,每个数据的值(0~255)由USB主机自己定义。
接下的一些说明描述符代码如下,就不详细介绍了:

/* 语言ID描述符 */ const uint8_t CustomHID_StringLangID[CUSTOMHID_SIZ_STRING_LANGID] = { CUSTOMHID_SIZ_STRING_LANGID, /*bLength:本描述符的长度为4字节*/ USB_STRING_DESCRIPTOR_TYPE, /*bDescriptorType:字符串描述符的类型为0x03*/ 0x09, /*bString:语言ID为0x0409,表示美式英语*/ 0x04 }; /* LangID = 0x0409: U.S. English*/ /*厂商字符串描述符*/ const uint8_t CustomHID_StringVendor[CUSTOMHID_SIZ_STRING_VENDOR] = { CUSTOMHID_SIZ_STRING_VENDOR, /*bLength:厂商字符串描述符的长度*/ USB_STRING_DESCRIPTOR_TYPE, /*bDescriptorType:字符串描述符的类型为0x03*/ ‘M’, 0, ‘y’, 0, ‘U’, 0,‘S’, 0,‘B’, 0, ‘_’, 0, ‘H’, 0,‘I’,0,‘D’,0 /*自定义*/ }; /*产品的字符串描述符*/ const uint8_t CustomHID_StringProduct[CUSTOMHID_SIZ_STRING_PRODUCT] = { CUSTOMHID_SIZ_STRING_PRODUCT, /* bLength:产品的字符串描述符*/ USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType:字符串描述符的类型为0x03*/ ‘B’, 0, ‘y’, 0, ’ ‘, 0, ‘v’, 0, ‘i’, 0, ‘e’, 0,‘w’,0,‘t’,0,‘o’,0,‘o’,0,‘l’,0/*自定义*/ }; /*产品序列号的字符串描述符*/ uint8_t CustomHID_StringSerial[CUSTOMHID_SIZ_STRING_SERIAL] = { CUSTOMHID_SIZ_STRING_SERIAL, /* bLength:产品序列号*/ USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType:字符串描述符的类型为0x03*/ ‘x’, 0, ‘x’, 0, ‘x’, 0,‘x’, 0,‘x’, 0, ‘x’, 0, ‘x’, 0 /*自定义*/ };


接下去需要改动的的是usb_prop.c这个文件里的内容。这个文件大部分不需要膝盖,只要修改下CustomHID_Reset()这个函数(名字不定相同)。这个函数的定义如下:

/******************************************************************************* * Function Name : CustomHID_Reset. * Description : CustomHID Mouse reset routine.复位 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void CustomHID_Reset(void) { /* Set CustomHID_DEVICE as not configured */ pInformation->Current_Configuration = 0; //设置当前的配置为0,表示没有配置过 pInformation->Current_Interface = 0;//默认的接口 /* Current Feature initialization */ pInformation->Current_Feature = CustomHID_ConfigDescriptor[7];//当前的属性,bmAttributes:设备的一些特性,0xc0表示自供电,不支持远程唤醒 #ifdef STM32F10X_CL /* EP0 is already configured in DFU_Init() by USB_SIL_Init() function */ /* Init EP1 IN snd EP1 OUT as Interrupt endpoint */ OTG_DEV_EP_Init(EP1_IN, OTG_DEV_EP_TYPE_INT, EP1_SIZE); OTG_DEV_EP_Init(EP1_OUT, OTG_DEV_EP_TYPE_INT, EP1_SIZE); #else SetBTABLE(BTABLE_ADDRESS); /*————————————————————————–*/ /* Initialize Endpoint 0 */ SetEPType(ENDP0, EP_CONTROL); //设置端点1为控制端点 SetEPTxStatus(ENDP0, EP_TX_STALL); //设置端点0发送延时 SetEPRxAddr(ENDP0, ENDP0_RXADDR); //设置端点0的接收缓冲区地址 SetEPTxAddr(ENDP0, ENDP0_TXADDR); //设置端点0的发送缓冲区地址 Clear_Status_Out(ENDP0); //清除端点0的状态 SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);//设置端点0的接收的计数 SetEPRxValid(ENDP0); //使能接收状态 /* Initialize Endpoint 1 */ SetEPType(ENDP1, EP_INTERRUPT); //设置端点1为中断控制端点 SetEPRxAddr(ENDP1, ENDP1_RXADDR); //设置端点1的接收缓冲地址 SetEPRxCount(ENDP1, REPORT_COUNT); //设置端点1的接收计数 SetEPRxStatus(ENDP1, EP_RX_VALID); //设置端点1接收有效 //SetEPTxStatus(ENDP1, EP_TX_DIS); /* Initialize Endpoint 2 */ SetEPType(ENDP2, EP_INTERRUPT); //设置端点2为中断控制端点 SetEPTxAddr(ENDP2, ENDP2_TXADDR); //设置端点2的接收缓冲地址 SetEPTxCount(ENDP2, REPORT_COUNT); //设置端点2的接收计数 SetEPTxStatus(ENDP2, EP_TX_NAK); //设置端点2为接收不响应

/*————————————————————————–*/ bDeviceState = ATTACHED; //设置设备状态为 ATTACHED状态 /* Set this device to response on default address */ SetDeviceAddress(0); //设置设备为默认地址 #endif /* STM32F10X_CL */ bDeviceState = ATTACHED; }

在两根”/*——*/“中间的代码是最重要的,我们根据配置描述可知,端点1作为输出端点,端点2作为输入端点,所以在Reset函数中需要对端点进行初始化:端点0在USB枚举阶段作为通讯的端点,要配置成控制端点,收发有效;端点1配置成中断传输端点,端点接收有效,发送无效;端点2配置成中断传输端点,端点发送有效。
我们在之前关于数据收发流程中说到,数据接收的流程: USB_LP_CAN1_RX0_IRQHandler—>USB_Istr—->CTR_LP—>EPx_OUT_Callback。所以我们这里首先需要定义USB中断服务程序 USB_LP_CAN1_RX0_IRQHandler,再还要编写端点接收回调函数: EPx_OUT_Callback函数。
在hw_config.c中编写USB中断配置函数:

void USB_Interrupts_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; /* 2 bit for pre-emption priority, 2 bits for subpriority */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); #ifdef STM32F10X_CL /* Enable the USB Interrupts */ NVIC_InitStructure.NVIC_IRQChannel = OTG_FS_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* Enable the USB Wake-up interrupt */ NVIC_InitStructure.NVIC_IRQChannel = OTG_FS_WKUP_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_Init(&NVIC_InitStructure); #else /* Enable the USB interrupt */ NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; //设置USB中断服务程序 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); #endif /* STM32F10X_CL */ }

我们这里只配置 USB_LP_CAN1_RX0_IRQn这个中断,接着在stm32f10x_it.c中编写 USB_LP_CAN1_RX0_IRQHandler()函数:

void USB_LP_CAN1_RX0_IRQHandler(void) { USB_Istr(); }

这个中断服务程序只调用USB_Istr()函数。经过这个函数的处理,最终程序会执行到 EPx_OUT_Callback函数,由于我们使用端点1作为接受数据的端点,所以我在usb_endp.c中编写 EP1_OUT_Callback()函数:

/******************************************************************************* * Function Name : EP1_OUT_Callback. * Description : 端点1输出回调函数 * Input : None. * Output : None. * Return : None. *******************************************************************************/ void EP1_OUT_Callback(void) { #ifndef STM32F10X_CL PMAToUserBufferCopy(USB_Receive_Buffer, ENDP1_RXADDR, REPORT_COUNT); //PMA缓冲区接收到的数据拷贝到用户自定义缓冲区USB_Receive_Buffer中 SetEPRxStatus(ENDP1, EP_RX_VALID); //设置端点的接收状态为有效,因为端点接收到数据后会端点状态自动设置成停止状态 USB_Received_Flag=1; //设置接收到数据标志位 #else USB_SIL_Read(EP1_OUT,USB_Receive_Buffer); //读取输出端点的数据到USB_Receive_Buffer中 USB_Received_Flag=1; //收到数据的标志 #endif }

这个函数起始很简单,从端点缓冲区中读取数据,保存在 USB_Receive_Buffer[]数组中,到时候,可以直接拿这个数组进行数据操作了。
我们还有编写一个端点发送函数:USB_SendData()。我在自己建的usb_io.c文件中,编写该函数:

/******************************************************************************* * Function Name : EP1_IN_Callback. * Description : USB向主机发送数据 * Input : None. * Output : None. * Return : None. *******************************************************************************/ uint32_t USB_SendData(uint8_t *data,uint32_t dataNum) { #ifndef STM32F10X_CL //将数据通过USB发送出去 UserToPMABufferCopy(data, ENDP2_TXADDR, dataNum); //拷贝dataNum个数据到PMA中 SetEPTxCount(ENDP2, REPORT_COUNT); //从端点2发送64字节数据 SetEPTxValid(ENDP2); //使能端点2的发送状态 #else USB_SIL_Write(EP2_IN, data, dataNum); #endif return dataNum; }

依旧很简单,只要来那个要发送的数据包写入端点的缓冲区中,再使能下短短,数据就看可以发送出去了。
最后,我们来编写我们的main函数:

/******************************************************** 函数:main() 描述:程序入口地址 参数:无 返回:无 ********************************************************/ int main(void) { uint8_t data[64]; uint32_t i=0,ret=0; BSP_Init(); printf(” |===============================================|\r\n”); printf(” USB CustomHID 程序开始 \r\n”); printf(“|===============================================|\r\n”); while(1) { if(USB_Received_Flag) { USB_Received_Flag=0; ret = USB_GetData(data,sizeof(data)); //读取数据 printf(“usb get data %d byte data\r\n”,ret); //答应接收到的字节数 for(i=0;i<ret;i++){ printf(“0x%02X “,data[i]); //答应接收到的数据 } printf(“\n\r”); USB_SendData(data,sizeof(data)); //发送接收到的数据 } } }

主函数的意思是,USB设备接收到什么数据,就向USB主机发送什么数据,并且在串口打印出收到的数据。
至此,CustomHID程序差不多了。万事俱备只欠东风了:我们还需要一个上位机的HID程序。可惜啊,这里上传不了,只能截个图让大家看看现象了。
 
再看看BUS Hound捕获到的数据,可以看到发送的数据和就收到的数据一样:
 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32-custom usb 的相关文章

  • STM32在Debug时程序运行时间不对,Debug时定时器中断每次进入断点时间不对,定时器一开启就进入中断的解决办法

    一 Debug时程序时间不对解决办法 1 点击魔术棒 2 点击Debug 点击Settings 3 点击Trace 在Core Clock里修改为你的系统时钟 二 Debug时定时器中断每次进入断点时间不对 在Debug时 程序停下来 定时
  • 如何更改闪存的起始地址?

    我正在使用 STM32F746ZG 和 FreeRTOS Flash的起始地址是0x08000000 但我想把它改成0x08040000 我通过谷歌搜索了这个问题 但没有找到解决方案 我更改了链接器脚本 如下所示 MEMORY RAM xr
  • 以字符串形式接收数字(uart)

    我正在尝试通过 uart 接收一个包装为字符串的数字 我发送数字 1000 所以我得到 4 个字节 空字符 但是 当我使用 atoi 将数组转换为数字并将整数与 1000 进行比较时 我并不总是得到正确的数字 这是我用于接收号码的中断处理函
  • 在 MCU 内部 FLASH 中从一个固件跳转到另一个固件

    我目前正在开发针对 STM32F030C8 的引导加载程序固件应用程序 我在分散文件中指定引导加载程序应用程序将占用主内存位置 0x08000000 到 0x08002FFF 扇区 0 到扇区 2 我还编写了一个主固件应用程序 存储在0x0
  • 当数据大小较小时,内存到内存 DMA 传输是否需要权衡?

    我正在学习 STM32 F4 微控制器 我正在尝试找出使用 DMA 的限制 根据我的理解和研究 我知道如果数据量较小 即设备使用DMA生成或消耗少量数据 则开销会增加 因为DMA传输需要DMA控制器执行操作 从而不必要地增加系统成本 我做了
  • 133-基于stm32单片机停车场车位管理系统Proteus仿真+源程序

    资料编号 133 一 功能介绍 1 采用stm32单片机 4位数码管 独立按键 制作一个基于stm32单片机停车场车位管理系统Proteus仿真 2 通过按键进行模拟车辆进出 并且通过程序计算出当前的剩余车位数量 3 将剩余的车位数量显示到
  • HAL库STM32常用外设教程(二)—— GPIO输入\输出

    HAL库STM32常用外设教程 二 GPIO输入 输出 文章目录 HAL库STM32常用外设教程 二 GPIO输入 输出 前言 一 GPIO功能概述 二 GPIO的HAl库驱动 三 GPIO使用示例 1 示例功能 四 代码讲解 五 总结
  • Push_back() 导致程序在进入 main() 之前停止

    我正在为我的 STM32F3 Discovery 板使用 C 进行开发 并使用 std deque 作为队列 在尝试调试我的代码 直接在带有 ST link 的设备上或在模拟器中 后 代码最终在 main 中输入我的代码之前在断点处停止 然
  • 匹配 STM32F0 和 zlib 中的 CRC32

    我正在研究运行 Linux 的计算机和 STM32F0 之间的通信链路 我想对我的数据包使用某种错误检测 并且由于 STM32F0 有 CRC32 硬件 并且我在 Linux 上有带有 CRC32 的 zlib 所以我认为在我的项目中使用
  • 毕业设计 江科大STM32的智能温室控制蓝牙声光报警APP系统设计

    基于STM32的智能温室控制蓝牙声光报警APP系统设计 1 项目简介 1 1 系统构成 1 2 系统功能 2 部分电路设计 2 1 stm32f103c8t6单片机最小系统电路设计 2 2 LCD1602液晶显示电路设计 2 2 风
  • STM32 GPIO工作原理详解

    STM32 GPIO介绍 1 STM32引脚说明 GPIO是通用输入 输出端口的简称 是STM32可控制的引脚 GPIO的引脚与外部硬件设备连接 可实现与外部通讯 控制外部硬件或者采集外部硬件数据的功能 以STM32F103ZET6芯片为例
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • 1.69寸SPI接口240*280TFT液晶显示模块使用中碰到的问题

    1 69寸SPI接口240 280TFT液晶显示模块使用中碰到的问题说明并记录一下 在网上买了1 69寸液晶显示模块 使用spi接口 分辨率240 280 给的参考程序是GPIO模拟的SPI接口 打算先移植到FreeRtos测试 再慢慢使用
  • STM32 暂停调试器时冻结外设

    当到达断点或用户暂停代码执行时 调试器可以停止 Cortex 中代码的执行 但是 当皮质停止在暂停状态下执行代码时 调试器是否会冻结其他外设 例如 DMA UART 和定时器 您只能保留时间 r 取决于外围设备 我在进入主函数时调用以下代码
  • STM32F4XX的12位ADC采集数值超过4096&右对齐模式设置失败

    文章目录 一 前言 二 问题1 数值超过4096 三 问题1的排错过程 四 问题2 右对齐模式设置失败 五 问题2的解决方法 5 1 将ADC ExternalTrigConv设置为0 5 2 使用ADC StructInit 函数 一 前
  • 库函数点亮Led

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 pandas是什么 二 使用步骤 1 引入库 2 读入数据 总结 前言 提示 这里可以添加本文要记录的大概内容 例如 随着人工智能的不断发展 机器学习这门
  • 特殊寄存器

    特殊寄存器 文章目录 前言 一 背景 二 2 1 2 2 总结 前言 前期疑问 STM32特殊寄存器到底是什么 特殊寄存器怎么查看和调试代码 本文目标 记录和理解特殊寄存器 一 背景 最近在看ucosIII文章是 里面提到特殊寄存器 这就进
  • systick定时器

    systick定时器 文章目录 前言 一 前期疑惑 二 解答 1 关于systick是阻塞的吗 2 非阻塞 三 软件编写 总结 前言 这边记录systick相关知识点 一 前期疑惑 在学习systick志气啊 其实对于systick还是一脸
  • 从没有中断引脚并且在测量准备好之前需要一些时间的传感器读取数据的最佳方法

    我正在尝试将压力传感器 MS5803 14BA 与我的板 NUCLEO STM32L073RZ 连接 根据 第 3 页 压力传感器需要几毫秒才能准备好读取测量值 对于我的项目 我对需要大约 10 毫秒来转换原始数据的最高分辨率感兴趣 不幸的
  • STM32 上的 ADC 单次转换

    我正在研究 STM32 F103x 上的 ADC 编程 并从最简单的情况 单次转换开始 测量内部温度传感器 连接到 ADC1 的值 并使用 USART 将其发送到 COM 端口 目标似乎很明确 但是当我尝试将源代码下载到闪存时 它不会向 C

随机推荐

  • 百度网盘登陆验证提示:无法访问此页面,或者二维码显示失败,弹窗显示:无法访问此页面,确保web地址。。。。

    百度网盘登陆验证提示 无法访问此页面 或者二维码显示失败 弹窗显示 无法访问此页面 确保web地址 遇到百度网盘登陆时显示下面的情况 原因 是自己电脑的IE浏览器设置出了问题 没有显示出来应有的验证界面 解决方案 打开电脑的IE浏览器 在右
  • Apex安装失败(笔记记录分享)

    Apex安装失败 笔记记录 1 错误合集 No 1 error detected in the compilation of csrc multi tensor scale kernel cu No 2 module torch nn ha
  • Java long Long

    转载 https www cnblogs com c2g5201314 p 13024261 html 1 long 是 基本类型 Long 是 对象类型 2 long 默认值是 0 Long 默认值是 null 3 比较方法 1 Long
  • LVS 就是这么简单(数字后端物理验证篇)

    LVS 就是这么简单 数字后端物理验证篇 文章右侧广告为官方硬广告 与吾爱IC社区无关 用户勿点 点击进去后出现任何损失与社区无关 今天吾爱 IC 社区小编为大家带来数字 IC 后端实现物理验证中关于 LVS 的主题分享 其实小编一直觉得这
  • 调整echarts中图与legend的距离

    1 正常调整legend的位置 通过X改变横坐标位置 通过Y改变纵轴位置 x 可设定图例在左 右 居中 y 可设定图例在上 下 居中 legend y bottom data 阳性转阴性 阴性转阳性 阳性无症状转有症状 未检测 2 如果觉得
  • STM32F103ZET6【标准库函数开发】------04 串口USART1控制LED

    一 硬件介绍 STM32F103ZET6有5个串口 查看引脚图可以找到对应的IO口分别如下 串口 USART1 USART2 USART3 UART4 UART5 输入 输出方式 USARTx TX PA9 PA2 PB10 PC10 PC
  • forcats

    引子 最近在整理forcats工具包中的函数 发现该包只有fct reorder2 函数的功能不太容易理解 所以单独写一篇推文来介绍它 根据上篇提到的函数分类 它可以归为 调整类别顺序的函数 与它类似的还有一个fct reorder 函数
  • 九龙战登录只显示一个服务器,九龙战登录失败进不去解决办法

    九龙战是腾讯推出的一款三国题材的动作竞技手游 目前已经开启了不删档测试 但是玩家们在游戏中遇到了登录失败进不去的情况 下面小编就为大家介绍一下九龙战登录失败进不去解决办法 首先玩家们要知道九龙战是一款不删档测试不久的游戏 所以在这期间出现什
  • Android基于BroadcastReceiver和Service、SoundPool开发的防过充助手app

    前段时间换了一个小米4C手机 可是发现它的充电充满没有提醒 上一个手机换了就是因为不爱惜电池 让它过充的次数多了 虽然听别人说小米4c手机充电器是智能充电器 有保护作用 但我自己还是不放心 于是就亲手写了一个防过充小应用 已经在使用 可以达
  • 如何使用LaTeX制作PPT?

    作为LaTeX排版软件 LaTeX主要被用来制作书籍和文章 但由于现代LaTeX系统主要以PDF文件为输出方式 授课 演讲用的计算机幻灯片也日益成为LaTeX的一个重要应用 LaTeX中专门用来制作幻灯片的工具有powerdot文档类 pr
  • 探索.NET:​构建现代软件开发的核心框架

    摘要 在现代软件开发领域 选择一个合适的开发框架对于成功构建可靠 高效的应用程序至关重要 NET 读作 dot net 是一个强大而广泛使用的框架 为开发人员提供了丰富的工具和功能 以简化开发过程并加快交付时间 本文将介绍 NET的基本概念
  • 【手撕RPC服务分几步】

    手撕RPC服务分几步 前言 什么是RPC 从被调用方 provider 来说 从调用方 consumer 来说 扩展思考 dubbo架构图 前言 本文试图通过手撕RPC的理论步骤来帮助我们更好的理解其特性 也更好的理解像Dubbo sofa
  • flutter 填坑之旅(dart学习笔记篇)

    俗话说 工欲善其事必先利其器 想要撸flutter app 而不懂 dart 那就像一个不会英语的人在和英国人交流 懵 安装 dart 就不用说了 比较简单dart 官网 https dart dev 安装完成后就开启学习dart 旅程吧
  • MyEclipse配置Tomcat7

    首先我们打开Myeclipse 进入偏好设置window gt perferences 进入偏好设置 perferences 在偏好设置的搜索栏那里输入tomcat查找tomcat 如下图所示 3 我们可以看到搜索到的有四个tomcat项
  • (笔试前准备)字符串匹配算法总结

    我想说一句 我日 我讨厌KMP KMP虽然经典 但是理解起来极其复杂 好不容易理解好了 便起码来巨麻烦 老子就是今天图书馆在写了几个小时才勉强写了一个有bug的 效率不高的KMP 特别是计算next数组的部分 其实 比KMP算法速度快的算法
  • STM32 HAL库更改中断向量表的偏移地址

    以STM32F767为例 打开system stm32f7xx c文件 定位VECT TAB OFFSET 更改此宏定义的值 即可更改偏移量
  • 富维火焰识别算法

    火灾是威胁公共安全 危害人民生命财产的灾害之一 加强消防安全管理是头等大事 对火灾做到早预防 早发现 尽量避免火灾的发生尤为重要 近年来随着网络摄像机的广泛使用以及图像处理技术的不断发展 基于视频的北京富维图像火焰识别算法得到了越来越多的关
  • Android Rom修改制作工具软件集合

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 1 SIN2IMG 用于固件ftf中system sin的解包 下载地址 SIN2IMG rar 使用方法 将固件ftf文件用rar打开 解压出system sin文件 将
  • Idea 修改默认的Maven配置及修改为阿里源

    每次使用Idea创建或者导入Maven项目的时候 Idea都会使用系统默认的Maven 此时 如果我们想使用自定义安装的Maven 需要在File gt other settings gt Settings for New Projects
  • STM32-custom usb

    如何建立一个自定义的HID工程呢 下面就来讲讲 首先先介绍下工程的架构 工程的总体架构下图所示 按照下图架构建工程 分析下工程布局 首先是APP 这个组里存放着主文件mian c 管理所有中断服务程序stm3210x it c 及其管理外设