1. 目的
在汽车电子开发中,CAN通讯是很难避开的一个技术点,当前CAN已经形成了行业内较为稳定的开发及相关测试验证方法,其中一种较为主流的就是使用CANoe和开发相应的CAPL脚本配合测试。然而,这套方案下来无论人力财力都是价格不菲,而且面对日异月新的技术发展也显得较为保守。所以笔者尝试使用树莓派配合MCP2515模块,进行低成本的CAN网络节点搭建和报文模拟,试图拓宽一下视野和思路。
本文针对普通外设和通讯外设,分别使用了Python 和 C进行编写控制,可以作为案例以便参考。
2. 材料准备
- 树莓派 zero w
- MCP2515模块
- 2路继电器模块
- linux 使用基础
3. 初始设置
树莓派安装最新的官方程序,安装好之后将ssh,gpio,spi等设置统统设为开启。
然后将树莓派连接到局域网wifi,进行ssh登录管理(此处也可使用usb网卡模式进行ssh连接,好处是免除连接屏幕进行系统初始设置)。
ssh连接成功后将树莓派换成国内的源(笔者使用的阿里的源),进行 sudo apt-get update
和 sudo apt-get upgrade
更新。
我们使用树莓派,需要进行GPIO设置和spi通讯,控制这两部分可以使用官方推荐的WringPi库,在官方系统中是默认安装的。经过如上操作后会将库更新至最新,使用gipo -v
进行版本查看,使用gpio readall
进行所有引脚定义查看。
除了WringPi库之外,树莓派还能够使用python进行GPIO的控制操作,导入RPi.GPIO模块即可。
4. GPIO 控制继电器
继电器模块采用[带光耦保护 2路 继电器模块],淘宝可以直接买到,该继电器模块是5v供电,需要两路输出IO进行低有效的控制,根据硬件特性选取树莓派如下引脚,与继电器模块进行连接。
4.1. 使用Python 的RPi.GPIO模块进行控制
针对继电器,可以使用python的RPi.GPIO模块进行控制,默认系统中会安装此模块,如果没有可以使用如下命令sudo pip3 install RPi.GPIO
进行安装。
根据模块物理特性,需要设置38,40两个引脚为低电平输出,设置37脚为PWM模式,使用如下代码进行设置。
import RPi.GPIO as GPIO
# Use BCM chip number as handle
GPIO.setmode(GPIO.BCM)
# Set useful channel
RELAY_1 = 20
RELAY_2 = 21
PWM_1 = 26
# Collect chip channel as setting list
output_list = [RELAY_1,RELAY_2,PWM_1]
# Set GPIO and PWM peripheral
GPIO.setup(output_list, GPIO.OUT, initial=GPIO.HIGH)
init_freq = 50 # initial frequency in Hz
pwm_pin37 = GPIO.PWM(PWM_1, init_freq)
# Set gpio as low output ,if high output then use GPIO.HIGH
GPIO.output(RELAY_1,GPIO.LOW)
# Start pwm ,initial duty cycle in 0.0 ,100.0
init_dc = 50
pwm_pin37.start(init_dc)
# Change frequency and duty cycle
para_freq = 60
para_duty = 20
pwm_pin37.ChangeFrequency(para_freq)
pwm_pin37.ChangeDutyCycle(para_duty)
# Stop PWM out
pwm_pin37.stop()
# Release system resource and close gpio control
GPIO.cleanup()
其中 PWM引脚输出电平最高为3.3V,输出波形较为工整,但是与设定的误差较大,当设定载频为1K时,实际测试为850Hz,设定载频为3K,实际输出2K,设定10K,实际输出3.6K。所以在使用PWM功能时需要实际测试输出的载频,在进行设定。
如下为载频设定为10K,实际输出3.6K的波形。
4.2. 使用WringPi库函数进行控制
WringPi库为C语言,需要进行编译后运行,与RPi的区别就是WringPi支持spi和iic通讯控制,后续进行CAN网络节点模拟也只能使用WringPi进行编写。如下为基本的设置函数示例,具体需要查看官方文档进行相应的函数调用及开发。
/*-----------------------------------------------------------------------------
Function : Used for testing RaspberryPi ZeroW's gpio pin -> Relay
FileName : TestRelay.c
Author : Tomato
Time : 2019.2.4
Version : 0.1
Notes : None
-----------------------------------------------------------------------------*/
#include <wiringPi.h>
#include <softPwm.h>
/* Macro config define */
#define RELAY_1 20U
#define RELAY_2 21U
#define PWM_1 26U
/* Parameter define */
static int high_edge_time = 0; // uint :0.1ms
static int cycle_time = 200; // uint :0.1ms
int main (void)
{
/* Initial gpio with chip pin ,if use mapping pin -> wiringPiSetup*/
wiringPiSetupGpio () ;
/* Set relay1&2 pwm pin as output */
pinMode (RELAY_1, OUTPUT) ; /* INPUT
OUTPUT
PWM_OUTPUT
GPIO_CLOCK
SOFT_PWM_OUTPUT
SOFT_TONE_OUTPUT
PWM_TONE_OUTPUT */
pinMode (RELAY_2, OUTPUT) ;
pinMode (PWM_1, SOFT_PWM_OUTPUT) ;
softPwmCreate(PWM_1,high_edge_time,cycle_time);
/* Main loop function */
for (;;)
{
/* Control relay */
digitalWrite (RELAY_1, HIGH) ;
delay (500) ;
digitalWrite (RELAY_1, LOW) ;
delay (500) ;
/* Control pwm */
softPwmWrite(PWM_1, 20); // duty = 20/cycle_time
delay (5000);
softPwmWrite(PWM_1, 50);
delay (5000);
softPwmWrite(PWM_1, 90);
delay (5000);
}
return 0 ;
}
编写好如上函数后,进行编译和链接,链接的时候需要使用 -lwringPi 这个指令,进行相应库函数的链接。如需要编译PWM引脚控制部分,则需要增加 -lpthread 链接指令。
gcc -o TestRelay TestRelay.c -lwiringPi -lpthread
编译成功后,使用sudo ./TestRelay
命令直接运行我们编译指定的程序标识名TestRelay
,实际可以看到继电器的切合,以及PWM输出。
如程序中设定,测试实际输出如下图所示,使用PWM控制有如下限制,
- PWM设定的程序跑在10ms的线程任务下,所以每s最多更改100次,
- 每操控一个GPIO引脚,CPU负载率会上升 0.5%左右,要根据当前树莓派的负载率进行合理设置,以保证有足够的资源进行外部通讯连接。
需要注意的是 PWM控制中,使用RPi 和WringPi所输入的参数的角度不同,如需要切换使用则要参考如上两个源码示例,进行测试。
5. 小结
至此已经能够正常操纵树莓派的GPIO和PWM接口了,后续我会讲CAN通讯的设计和使用。