基于STM32F4的CANOpen移植教程(超级详细)

这篇具有很好参考价值的文章主要介绍了基于STM32F4的CANOpen移植教程(超级详细)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本专题相关教程:
基于STM32F4的CANOpen移植教程

基于STM32F4的CANopen快速SDO通信

linux下CANopen for python的使用

基于Linux C的CANopen移植

CANopen补充–时间计算出错

CANopen补充–主站检测节点是否在线

前言

为了在STM32F4上能够运行CANopen(CanFestival),跟着网上的教程操作,发现总是不够详细。主要是配置和代码运行部分基本没有解释。为了后来者能够少走弯路,便有了这篇教程。关于CANopen协议本身本文不做过多介绍,主要是介绍如何使用软件和代码修改。

本文配套资料下载地址:https://pan.baidu.com/s/1FMp7xuJ1r3gJTPB0wf3Yrw?pwd=osxs
提取码:osxs
基于STM32F4的CANOpen移植教程(超级详细)
废话不多说,GOGOGO。

1 物品准备

名称 用途
USB-CAN模块/USB-CAN盒子 用以监听数据(如实在没有的话,代码里添加串口反馈也勉强能测试)
Canfestival- 3 源代码 CANopen源代码 /本文资料里有
STM32F4 裸工程 移植目标平台代码,这里用正点原子的空白工程即可 /本文资料里有
CANopen轻松入门.pdf-周立功 pdf书籍,用以学习CANopen协议 /本文资料里有

USB-CAN模块,比如下面这个,买啥都行,有这个功能就ok。
基于STM32F4的CANOpen移植教程(超级详细)

USB-CAN盒子,如下,相比模块,多了一些功能(我用的就这个,不过好像多的功能我并没有用上)
基于STM32F4的CANOpen移植教程(超级详细)

CANopen轻松入门.pdf-周立功链接 下载地址

2 相关软件安装

2.1 CAN上位机

如果使用USB-CAN盒子,找店家要上位机资料即可。比如我用的这款资料如下:

驱动:驱动下载
驱动安装教程:驱动安装视频

上位机软件:上位机下载地址
基于STM32F4的CANOpen移植教程(超级详细)
基于STM32F4的CANOpen移植教程(超级详细)
打开设备-选择设备-选择对应波特率即可。

如果是普通的USB-CAN模块,找店家应该也有资料。使用CANpro协议平台分析软件即可,这个网上搜很容易搜得到。附一个我随便找的链接:CANPro协议分析平台官方下载

基于STM32F4的CANOpen移植教程(超级详细)

基于STM32F4的CANOpen移植教程(超级详细)

同理,启动-选择设备(不对就反复选)-选择波特率。

2.2 对象字典生成工具objdictedit环境配置

​ CANopen需要使用到字典,路径:源代码/objdictgen/objdictedit.py。这是个基于python2.7才能运行的程序,因此我们先装环境。
基于STM32F4的CANOpen移植教程(超级详细)

安装环境,遇到了很多坑。主要是网上教程很多偏老,跟着操作,各种bug。最终成功的一个搭配是

软件名字 备注
python-2.7.15.amd64.msi
wxPython3.0-win64-3.0.2.0-py27.exe 使用2.8会导致在安装下边软件的时候,提示包缺失
Gnosis_Utils-1.2.2.zip

安装教程参考:CanFestival中对象字典编辑器objdictedit的正确打开环境_lei_g的博客-CSDN博客_canfestival中对象字典编辑器的打开

备注:python2.7和自己之前安装的如python3.7是不冲突的。

要使用objdictedit,可以使用这个方式固定到任务栏。方便以后打开。

选择默认程序–>更多应用–>在这台电脑上查找其他应用–>选择python2.7文件夹里的python.exe
基于STM32F4的CANOpen移植教程(超级详细)
基于STM32F4的CANOpen移植教程(超级详细)
基于STM32F4的CANOpen移植教程(超级详细)

当打开下边程序的时候,在桌面任务栏选择:固定到任务栏。那么以后都可以右键这个图标,点击上边的objdictedit.py即可打开软件。
基于STM32F4的CANOpen移植教程(超级详细)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8awyPdNN-1646308038808)(C:\Users\FEN\AppData\Roaming\Typora\typora-user-images\image-20220303104232531.png)]

3 将CANopen移植到STM32F407

首先,这是我给大家准备的礼物,截图如下:
基于STM32F4的CANOpen移植教程(超级详细)

名称 说明
CanFestival-3源码 内含1个官方源码与3个分支,我们使用Mongo-canfestival,因为它有对于cm4内核的支持
CANopen裸工程 本教程所使用的空白代码
CANopen最终移植代码 本教程所使用的移植好的最终代码
USBCAN调试软件 USB-CAN盒子的上位机
字典工具安装 字典工具安装所需文件

3.1 基础代码移植

打开我们的空白工程,界面如图,空空如也。需要说明的是,个人喜欢把所有头文件放入main.h,这样其他外设文件只用包含main.h即可。
基于STM32F4的CANOpen移植教程(超级详细)

文件夹如下:
基于STM32F4的CANOpen移植教程(超级详细)

我们新建一个文件夹,名为CANopen,用于存放所有与CANopen有关的代码。
基于STM32F4的CANOpen移植教程(超级详细)

里面再新建几个子文件夹。

基于STM32F4的CANOpen移植教程(超级详细)

说明如下:

文件夹名 说明
dictionary 存放字典和其对应的.c /.h 文件
hardware 外设的驱动文件,如定时器,CAN,还有配置文件
inc 由CANopen源代码移植过来的h文件
src 由CANopen源代码移植过来的c文件

3.11 h文件移植

进入源代码/include目录,先将该目录下19个h文件,都复制到新工程/CANopen/inc 里,再复制cm4文件夹(内含3个h文件)更名为stm32。如下:
基于STM32F4的CANOpen移植教程(超级详细)

修改一下stm32/canfestival.h文件,添加3行语句,防止递归调用。
基于STM32F4的CANOpen移植教程(超级详细)

进入源代码\examples\AVR\Slave目录,把config文件,移植到新工程/CANopen/hardware
基于STM32F4的CANOpen移植教程(超级详细)

并对config做一点修改。
基于STM32F4的CANOpen移植教程(超级详细)

3.12 c文件移植

进入源代码/src目录,将该目录下除了symbols.c之外的12个c文件,复制到新工程/CANopen/src 里。
基于STM32F4的CANOpen移植教程(超级详细)

删除dcf.c文件下第59、98行前面的“inline”关键字
基于STM32F4的CANOpen移植教程(超级详细)
基于STM32F4的CANOpen移植教程(超级详细)

3.2 建立自己的底层驱动文件

​ 在裸工程/CANopen/hardware下新建定时器、CAN的c/h文件。其中定时器用于时间获取,CAN是通信基础。

需要说明的是,CANopen源代码里含有timer.c 文件,为了命名不冲突,我这里起名加了后缀。比如使用定时器3,就建立timer3.c。

如图,我们使用了can1,timer2, config.h为之前移植的文件,不用管。

基于STM32F4的CANOpen移植教程(超级详细)

文件 说明
can1 中断优先级为1(无所谓);波特率设置为1M(1M或者500K都行,要与config.h一致)
timer2 中断优先级1(无所谓);时钟84M,分频840,即基础频率为100K(要求与timerscfg.h里的配置即可),重装载值为65535,即0.65s一次溢出中断

can与timer的代码移植自源代码/drivers/cm4。cm4是基于stm32F3的,因此有些代码需要修改
基于STM32F4的CANOpen移植教程(超级详细)

cm4.c里面包含can1与timer3的初始化代码以及一些封装好的代码。我们将其各自复制到can1.c和timer3.c。并根据板子情况做修改。
基于STM32F4的CANOpen移植教程(超级详细)

大家可以到移植成功的工程里看看有啥修改。

can1.c

#include "can1.h"

static CO_Data *co_data = NULL;


//Initialize the CAN hardware 
unsigned char CAN1_Init(CO_Data * d, uint32_t bitrate)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  NVIC_InitTypeDef  NVIC_InitStructure;
  CAN_InitTypeDef        CAN_InitStructure;
  CAN_FilterInitTypeDef  CAN_FilterInitStructure;

  /* save the canfestival handle */  
  co_data = d;

  /* CAN GPIOs configuration **************************************************/

  /* Enable GPIO clock */
  RCC_AHB1PeriphClockCmd(CAN_GPIO_CLK, ENABLE);

  /* Connect CAN pins to AF7 */
  GPIO_PinAFConfig(CAN_GPIO_PORT, CAN_RX_SOURCE, GPIO_AF_CANx);
  GPIO_PinAFConfig(CAN_GPIO_PORT, CAN_TX_SOURCE, GPIO_AF_CANx); 

  /* Configure CAN RX and TX pins */
  GPIO_InitStructure.GPIO_Pin = CAN_RX_PIN | CAN_TX_PIN;
  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_UP;
  GPIO_Init(CAN_GPIO_PORT, &GPIO_InitStructure);

  /* NVIC configuration *******************************************************/
  NVIC_InitStructure.NVIC_IRQChannel = CANx_RX0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* CAN configuration ********************************************************/  
  /* Enable CAN clock */
  RCC_APB1PeriphClockCmd(CAN_CLK, ENABLE);

  /* CAN register init */
  CAN_DeInit(CANx);
  CAN_StructInit(&CAN_InitStructure);

  /* CAN cell init */
  CAN_InitStructure.CAN_TTCM = DISABLE;
  CAN_InitStructure.CAN_ABOM = DISABLE;
  CAN_InitStructure.CAN_AWUM = DISABLE;
  CAN_InitStructure.CAN_NART = DISABLE;
  CAN_InitStructure.CAN_RFLM = DISABLE;
  CAN_InitStructure.CAN_TXFP = DISABLE;
  CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
  CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
    
  /* CAN Baudrate (CAN clocked at 42 MHz)  42e6 / ( 6 * (1+BS1+BS2))  */
  CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
  if(bitrate == 1000000){
  	CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;
  	CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq;
  }
  else {	//除去1M频率。剩下都配置为500K
  	CAN_InitStructure.CAN_BS1 = CAN_BS1_6tq;
  	CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq;
  }

  CAN_InitStructure.CAN_Prescaler = 6;
  CAN_Init(CANx, &CAN_InitStructure);

  /* CAN filter init */
  CAN_FilterInitStructure.CAN_FilterNumber = 0;
  CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
  CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
  CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
  CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
  CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
  CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
  CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
  CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
  CAN_FilterInit(&CAN_FilterInitStructure);

  /* Enable FIFO 0 message pending Interrupt */
  CAN_ITConfig(CANx, CAN_IT_FMP0, ENABLE);

  return 1;
}

// The driver send a CAN message passed from the CANopen stack
unsigned char canSend(CAN_PORT notused, Message *m)
{
	int i, res;
	CanTxMsg TxMessage = {0};
	TxMessage.StdId = m->cob_id;
	TxMessage.IDE = CAN_ID_STD;
	if(m->rtr)
  		TxMessage.RTR = CAN_RTR_REMOTE;
	else
  		TxMessage.RTR = CAN_RTR_DATA;
	TxMessage.DLC = m->len;
	for(i=0 ; i<m->len ; i++)
		TxMessage.Data[i] = m->data[i]; 
    res = CAN_Transmit(CANx, &TxMessage);
	if(res == CAN_TxStatus_NoMailBox)
		return 0; 	// error
    return 1;		// succesful
}

//The driver pass a received CAN message to the stack
/*
unsigned char canReceive(Message *m)
{
}
*/
unsigned char canChangeBaudRate_driver( CAN_HANDLE fd, char* baud)
{
	return 0;
}

/**

  * @brief  This function handles CAN1 RX0 interrupt request.
  * @param  None
  * @retval None
    */
    void CAN1_RX0_IRQHandler(void)
    {
    int i;
    CanRxMsg RxMessage = {0};
    Message rxm = {0};
    CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
    // Drop extended frames
    if(RxMessage.IDE == CAN_ID_EXT) //不处理扩展帧
    	return;
    rxm.cob_id = RxMessage.StdId;

  	if(RxMessage.RTR == CAN_RTR_REMOTE)//远程帧
  		rxm.rtr = 1;
  	rxm.len = RxMessage.DLC;
  	for(i=0 ; i<rxm.len ; i++)
  		 rxm.data[i] = RxMessage.Data[i];
  
  	canDispatch(co_data, &rxm);//CANopen自身的处理函数,因为快速SDO不需要反馈,所以在上边处理后就不需要调用这步了

}

can1.h

#ifndef __CAN1_H
#define __CAN1_H

#include "sys.h"
#include "main.h"
#include "data.h"
// CAN bus defines for cortex-M4 STM32F407

#define CANx                       CAN1
#define CAN_CLK                    RCC_APB1Periph_CAN1
#define CAN_RX_PIN                 GPIO_Pin_11
#define CAN_TX_PIN                 GPIO_Pin_12
#define CAN_GPIO_PORT              GPIOA
#define CAN_GPIO_CLK               RCC_AHB1Periph_GPIOA
#define CANx_RX0_IRQn               CAN1_RX0_IRQn

#define GPIO_AF_CANx               GPIO_AF_CAN1
#define CAN_RX_SOURCE              GPIO_PinSource11
#define CAN_TX_SOURCE              GPIO_PinSource12

unsigned char CAN1_Init(CO_Data * d, uint32_t bitrate);

#endif 


timer3.c

#include "timer3.h"

TIMEVAL last_counter_val = 0;
TIMEVAL elapsed_time = 0;

// Initializes the timer, turn on the interrupt and put the interrupt time to zero
void TIM3_Init(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	/* TIM3 clock enable */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

	/* Enable the TIM3 gloabal Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	/* Compute the prescaler value */
	uint16_t PrescalerValue =840-1; //84M频率/840为100k(与timerscfg.h配置一致即可),即10us间隔

	/* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period = 65535;
	TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
	TIM_ClearITPendingBit(TIM3, TIM_SR_UIF);
 
	/* TIM3 enable counter */  //这里需要启动定时器
	TIM_Cmd(TIM3, ENABLE);

	/* Preset counter for a safe start */
	TIM_SetCounter(TIM3, 1);

	/* TIM Interrupts enable */
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
}

//Set the timer for the next alarm.
void setTimer(TIMEVAL value)
{
  	uint32_t timer = TIM_GetCounter(TIM3);        // Copy the value of the running timer
	elapsed_time += timer - last_counter_val;
	last_counter_val = 65535-value;
	TIM_SetCounter(TIM3, 65535-value);
	TIM_Cmd(TIM3, ENABLE);
	//printf("setTimer %lu, elapsed %lu\r\n", value, elapsed_time);
}

//Return the elapsed time to tell the Stack how much time is spent since last call.
TIMEVAL getElapsedTime(void)
{
  	uint32_t timer = TIM_GetCounter(TIM3);        // Copy the value of the running timer
	if(timer < last_counter_val)
		timer += 65535;
	TIMEVAL elapsed = timer - last_counter_val + elapsed_time;
	//printf("elapsed %lu - %lu %lu %lu\r\n", elapsed, timer, last_counter_val, elapsed_time);
	return elapsed;
}

// This function handles Timer 3 interrupt request.
void TIM3_IRQHandler(void)
{
	//printf("--\r\n");
	if(TIM_GetFlagStatus(TIM3, TIM_SR_UIF) == RESET)
		return;
	last_counter_val = 0;
	elapsed_time = 0;
	TIM_ClearITPendingBit(TIM3, TIM_SR_UIF);
	TimeDispatch();
}

timer3.h

#ifndef __TIMER3_H
#define __TIMER3_H

#include "sys.h"
#include "main.h"

void TIM3_Init(void);

#endif 

2022年3月18日记:
定时器实现函数存在缺陷,当超过一个功能需要调用时间时,会存在干涉。各位如果除了心跳报文发送之外,没用到其他需要时间的功能(节点掉线检测/pdo之类),那么可以忽略。不然可以看一下这个CANopen补充–时间计算出错。

3.3 建立词典

基于STM32F4的CANOpen移植教程(超级详细)
我们起名字为Master,使用心跳管理,这样我们待会便可以通过心跳报文来判断移植成功与否。

在字典里设置心跳报文间隔为1000ms(0x3E8)。这样,它每隔1000ms就会发送一个心跳报文。
基于STM32F4的CANOpen移植教程(超级详细)

点击保存,将生成的.od文件放入CANopen/dictionnary文件夹。
基于STM32F4的CANOpen移植教程(超级详细)

再点击建立词典,同样将生成的.c文件放入CANopen/dictionnary文件夹。
基于STM32F4的CANOpen移植教程(超级详细)

效果如下:
基于STM32F4的CANOpen移植教程(超级详细)

文件 说明
.od文件 词典工程文件,用于配置,不会被工程调用
.c .h 词典文件对应的c和h文件。需要被工程调用

3.4工程配置

文件都弄好了,我们打开keil软件,将这些文件都加入到工程。

3.41 c文件添加

基于STM32F4的CANOpen移植教程(超级详细)

在Groups里新建两个文件夹。需要说明的时候,为了美观,这里把词典文件和外设驱动文件放在一起了。

文件夹 说明
CANopen 含CANopen/src
CANopen_Driver 含CANopen/hardware 和CANopen/dictionary。
基于STM32F4的CANOpen移植教程(超级详细)
基于STM32F4的CANOpen移植教程(超级详细)

3.42 头文件路径添加

基于STM32F4的CANOpen移植教程(超级详细)
基于STM32F4的CANOpen移植教程(超级详细)

3.43 c99标准选择

由于源码很多地方,把定义语句放在赋值语句之后,这只在C99标准之后允许,因此勾选C99模式。
基于STM32F4的CANOpen移植教程(超级详细)

3.44 调试串口设置

​ 使用工程自带的USART1。

警告,在项目中正常运行后,一定要关闭调试功能,不然串口发送数据会严重降低相应速度!!!!!

我们打开applicfg.h ,如果找不到,直接全局搜索:MSG(…) 便可定位到啦。

第一,添加debug的定义 再次警告,在项目中正常运行后,记得关闭(把定义注释掉);第二,把打印函数里的\n 改成\r\n。
基于STM32F4的CANOpen移植教程(超级详细)

如图是串口反馈的效果,还是挺直观的。没有USB-CAN的同学可以通过串口调试助手来观察。

基于STM32F4的CANOpen移植教程(超级详细)

3.45 程序启动

首次,在main.h里添加相关头文件

基于STM32F4的CANOpen移植教程(超级详细)

main函数添加canopen初始化。包含定时器3、串口1、can1的初始化

#include "sys.h"	
#include "main.h"		

int main(void)
{ 
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
    delay_init(168);    	//初始化延时函数

    TIM3_Init();
    USART1_Init(115200);
    CAN1_Init(&Master_Data,1000000);

    unsigned char nodeID = 0x00;                   //主站ID
    setNodeId(&Master_Data, nodeID);
    setState(&Master_Data, Initialisation);		 //节点初始化
    setState(&Master_Data, Operational);		
	
	while(1)
	{
		delay_ms(1000);
	}
}

下载,启动!

使用软件观察。

基于STM32F4的CANOpen移植教程(超级详细)

心跳没有问题,nice
如果大家有需要让主站检测节点是否掉线的需要,可以看CANopen补充–主站检测节点是否在线。

4 末尾

​ 到这里便移植成功啦。下一篇教程基于STM32F4的CANopen快速SDO通信(超级详细)

文章来源地址https://www.toymoban.com/news/detail-432892.html

到了这里,关于基于STM32F4的CANOpen移植教程(超级详细)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于STM32F4开发的智能台灯

    写这篇博客的目的有2个,首先是记录一下学习STM32大半年来的第一个自己动手开发的项目,整理一下开发过程和思路;其次也是希望可以和更多的同行交流开发经验,有什么问题可以多多讨论,集思广益,共同进步~ 开发的智能台灯功能有2个: 1.手动模式:可通过按键调节

    2024年02月05日
    浏览(41)
  • 基于STM32F4的多摩川协议通讯

    1、介绍        之前项目刚好有用到禹衡家的17位绝对值编码器,趁着周末有时间整理一下开发思路,同时也分享出来给有需要的人做做参考。        说回编码器,我们都知道在伺服控制中,为了获取更高的位置精度,完成更精细的绝对定位,通常会采用绝对式光电编码

    2024年02月11日
    浏览(44)
  • STM32F4 基于USART串口的蓝牙通信

    目录 一、硬件资源 连接方案 其他配置 二、实验原理 基本定义 USART介绍 USART工作原理 数据发送 数据接收 蓝牙HM-10配置 三、代码部分 usart.c usart.h Serial.c Serial.h main.c 结语 STM32F401,OLED,蓝牙hm10 连接方案 设备1的TX与设备2的RX连接,这样设备1发送的数据可以被设备2接收到。

    2024年01月17日
    浏览(46)
  • 【stm32开发笔记】基于HAL库的STM32F4添加DSP库

    本文分两种方法添加DSP库:1.CubeMX直接配置ioc添加; 2.KEIL内添加; 简述:补齐全部lib库-添加DSP包-使能DSP勾选-添加头文件及魔术棒配置-测试 1.补齐lib库。( 如果使用直接默认添加的库,是不支持FPU的,所以需要补齐后找到所需的lib文件进行替换,在MX的工程管理栏,选择复制所

    2024年02月16日
    浏览(54)
  • 【CANopen】关于STM32的CanFestival移植

    使用STM32F407单片机 CanFestival下载 默认都会,略 在CubeMX生成代码路径下创建一个文件夹,将 源码目录下的include和src 两个文件夹复制进去 首先是 include 文件夹,如图所示, 其中,timers.h大概率会和CubeMX中生成的文件名重名,所以需要重命名 这个文件夹改名后需要修改 srctim

    2024年01月17日
    浏览(41)
  • FreeRTOS移植STM32超详细(以STM32F103ZE为例)

    我刚学FreeROTS时想移植到STM32,找了网上很多资料,但大多都不是很完整,于是我把我自己的移植过程分享出来,供大家参考。 我们以STM32F103ZE,正点原子的跑马灯实验为例, 准备工作: 跑马灯实验工程 FreeRTOS文件源码(可在官方下载)     第一步  移植文件到工程 首先在工

    2024年02月08日
    浏览(35)
  • 关于LWIP用法之HTTPD:基于STM32F4搭建web服务器

    一,STM32CUBEMX配置(使用的是6.4.0版本) 前提是在配置好LWIP的情况下(能ping通你的开发板),使能HTTPD功能。 然后是使能LWIP_HTTPD_CGI, 使能:LWIP_HTTPD_SUPPORT_POST(), 使能 :HTTPD_USE_CUSTOM_FSDATA。 会发现fs.c这个文件的#include HTTPD_FSDATA_FILE,这一句编译报错,解决办法:1) 在KEIL中lwipop

    2023年04月08日
    浏览(34)
  • 运动控制器设计——基于FreeModbus在STM32F4平台实现ModbusTCP和ModbusRTU

    本文笔者最近的项目是设计一款运动控制器,MCU使用的是STM32F429,要求是通过Modbus TCP协议实现与示教器通讯,并通过ModbusRTU实现与触摸屏通讯。 本文将介绍在STM32F4上实现 ModbusTCP和ModbusRTU通讯 的过程。笔者才疏学浅,如有错误还请指正。 Modbus协议是典型的主-从通讯结构,链

    2024年02月05日
    浏览(50)
  • 【极海APM32F4xx Tiny】学习笔记06-移植 RTT NANO工程,源码放在自己工程下的移植

    复制内容有bsp任意板子的rtconfig.h board.c 文件到 rtt nano目录,复制组件文件夹,头文件夹,源码文件夹,平台先关的libcpu文件夹 极海的这个mcu是M4的平台,的context_rvds 和 cpuport.c 修改地方 这里没有改,添加了注释

    2024年02月08日
    浏览(43)
  • 全网最简单的stm32f103c8t6移植ucosiii教程(附移植好的工程)

       最近在做一个机器人项目,需要使用到stm32f103c8t6核心板。考虑程序中的多任务特性,因此决定使用ucosiii用于多任务管理。ucosiii移植可能对于一些嵌入式老鸟来说,可能是信手拈来,但是对于很多新手特别是刚入门的小白来说还是有一定的难度的。尤其是全网的移植教程

    2024年02月16日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包