目录
1. linux 下can编程使用socket,在进行can编程之前需要先用命令设置好can的参数
1. linux 下can编程使用socket,在进行can编程之前需要先用命令设置好can的参数
# 在/etc/rc.local
ip link set can0 type can bitrate 250000 # 设置CAN0波特率250k
ip link set can1 type can bitrate 250000 # 设置CAN1波特率250k
ifconfig can0 up # 打开 can0
ifconfig can1 up # 打开 can0
/sbin/getty -n -l /home/root/auto_log_in.sh 115200 ttymxc0 # 开机自动登录脚本auto_log_in.sh里面: /bin/login -f root
注意:先设置CAN的参数,在ifconfig can up。
2.程序使用三个线程实现
主线程初始化can socket 和 CAN发送接收buffer 然后创建 CAN发送和接收线程,CAN发送线程检查CAN发送buffer里面是否包含待发送的can报文,CAN接收线程把报文存储到CAN的接收buffer 里面。注:usleep(0) 是主动让出接收发送时机。以下是具体代码实现。
#ifndef __CAN_DRIVER_H
#define __CAN_DRIVER_H
/*
struct can_frame {
canid_t can_id;//CAN 标识符
__u8 can_dlc;//数据场的长度
__u8 data[8];//数据
};
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <signal.h>
/*定义can缓存区大小*/
#define CAN_FRAME_BUFFER_SIZE 1024
/*定义缓冲区结构体*/
typedef struct CAN_BUFFER{
struct can_frame frame_buf[CAN_FRAME_BUFFER_SIZE];
unsigned int out;
unsigned int in;
}can_buf_struct;
/*can 0发送函数 填充数据到发送缓存区*/
int can0_tx(struct can_frame *fram);
/*can 0接受函数 从接收缓存区获取接收到的CAN一帧数据*/
int can0_rx(struct can_frame *fram);
/*打印 can_frame 帧数据内容*/
void print_can_frame(struct can_frame *frame);
int can_rx_tx_init(void);
#endif
#include "can_driver.h"
#define CAN_ZERO "can0"
#define debug_print printf
static volatile can_buf_struct can0_rx_buf;
static volatile can_buf_struct can0_tx_buf;
static pthread_mutex_t can0_lock;
static pthread_t thread_read_id=0;
static pthread_t thread_write_id=0;
static int sockfd = -1;
static void * can0_send(void *v);
static void * can0_recive(void *v);
static void pthread_quit_slot(int sig);
/*can 0发送函数 填充数据到发送缓存区*/
int can0_tx(struct can_frame *fram)
{
int ret=0;
// debug_print("can0_tx in = %d out = %d\r\n",can0_tx_buf.in,can0_tx_buf.out);
memcpy(&can0_tx_buf.frame_buf[can0_tx_buf.in],
fram,sizeof(struct can_frame));
can0_tx_buf.in++;
if(can0_tx_buf.in>=CAN_FRAME_BUFFER_SIZE){
can0_tx_buf.in = 0;
}
if(can0_tx_buf.in==can0_tx_buf.out){
debug_print("can0_tx_buf fill \r\n");
}
// pthread_mutex_lock(&can0_lock);
// send frame to can 0
// ret = write(sockfd, fram, sizeof(struct can_frame));
// pthread_mutex_unlock(&can0_lock);
return 0;
}
/*can 0接受函数 从接收缓存区获取接收到的CAN一帧数据*/
int can0_rx(struct can_frame *fram)
{
if(can0_rx_buf.in==can0_rx_buf.out){
return -1;
}else{
memcpy(fram,&can0_rx_buf.frame_buf[can0_rx_buf.out],sizeof(struct can_frame));
can0_rx_buf.out++;
if(can0_rx_buf.out>=CAN_FRAME_BUFFER_SIZE){
can0_rx_buf.out = 0;
}
}
return 0;
}
/*can0 初始化函数*/
static void can_rx_tx_release(int sig)
{
(void)sig;
if(thread_read_id>0)pthread_kill(thread_read_id,SIGQUIT);
if(thread_write_id>0)pthread_kill(thread_write_id,SIGQUIT);
if(thread_read_id)pthread_join(thread_read_id,NULL);
if(thread_write_id)pthread_join(thread_write_id,NULL);
if(sockfd>0)close(sockfd);
}
int can_rx_tx_init(void)
{
struct ifreq ifr = {0};
struct sockaddr_can can_addr = {0};
int ret;
can0_rx_buf.in = 0;
can0_rx_buf.out = 0;
can0_tx_buf.in = 0;
can0_tx_buf.out = 0;
pthread_mutex_init(&can0_lock,NULL);
/* 打开套接字 */
sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if(0 > sockfd) {
perror("socket error");
debug_print("socket error");
exit(EXIT_FAILURE);
}
/* 指定can0设备 */
strcpy(ifr.ifr_name, CAN_ZERO);
ioctl(sockfd, SIOCGIFINDEX, &ifr);
can_addr.can_family = AF_CAN;
can_addr.can_ifindex = ifr.ifr_ifindex;
/* 将can0与套接字进行绑定 */
ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
if (0 > ret) {
perror("bind error");
debug_print("bind error");
close(sockfd);
exit(EXIT_FAILURE);
}
ret = pthread_create(&thread_read_id, NULL,can0_recive, &sockfd);
if (0 > ret) {
debug_print(" read pthread_create fail\r\n");
}
ret = pthread_create(&thread_write_id, NULL,can0_send, &sockfd);
if (0 > ret) {
debug_print(" write pthread_create fail\r\n");
}
signal(SIGQUIT,can_rx_tx_release);
return 0;
}
/*私有函数 can0发送缓冲区数据*/
static void * can0_send(void *v)
{
int *p = v;
int sockfd = *p;
int ret=0;
//= (int)(*v);
struct can_frame *frame;
signal(SIGQUIT,pthread_quit_slot);
while(1){
// debug_print("%s,%d\r\n",__FUNCTION__,__LINE__);
if(can0_tx_buf.in==can0_tx_buf.out){
// debug_print("can0_tx_buf empty \r\n");
}else{
debug_print("%s,%d\r\n",__FUNCTION__,__LINE__);
frame = &can0_tx_buf.frame_buf[can0_tx_buf.out];
can0_tx_buf.out++;
if(can0_tx_buf.out >= CAN_FRAME_BUFFER_SIZE){
can0_tx_buf.out = 0;
}
pthread_mutex_lock(&can0_lock);
// send frame to can 0
ret = write(sockfd, frame, sizeof(struct can_frame));
pthread_mutex_unlock(&can0_lock);
if(ret!=sizeof(struct can_frame)){
debug_print("send can frame error\r\n");
}
}
usleep(0);
}
return NULL;
}
/*私有函数 can0接收数据到缓冲区*/
static void * can0_recive(void *v)
{
int *p = v;
int sockfd = *p;
int ret=0;
struct can_frame frame;
signal(SIGQUIT,pthread_quit_slot);
while(1){
pthread_mutex_lock(&can0_lock);
ret = read(sockfd, &frame, sizeof(struct can_frame));
pthread_mutex_unlock(&can0_lock);
if (0 > ret) {
debug_print("read can frame error %s,%d",__FUNCTION__,__LINE__);
// break;
}else{
debug_print("%s,%d\r\n",__FUNCTION__,__LINE__);
memcpy(&can0_rx_buf.frame_buf[can0_rx_buf.in],&frame,sizeof(struct can_frame));
can0_rx_buf.in++;
if(can0_rx_buf.in >= CAN_FRAME_BUFFER_SIZE){
can0_rx_buf.in = 0;
}
if(can0_rx_buf.in==can0_rx_buf.out){
debug_print("can0_rx_buf fill \r\n");
}
usleep(0);
// print_can_frame(&frame);
}
}
return NULL;
}
static void pthread_quit_slot(int sig)
{
(void)sig;
pthread_exit(0);
}
/*打印 can_frame 帧数据内容*/
void print_can_frame(struct can_frame *frame)
{
/* 校验帧格式 */
if (frame->can_id & CAN_EFF_FLAG) //扩展帧
printf("扩展帧 <0x%08x> ",frame->can_id & CAN_EFF_MASK);
else //标准帧
printf("标准帧 <0x%03x> ",frame->can_id & CAN_SFF_MASK);
/* 校验帧类型:数据帧还是远程帧 */
if (frame->can_id & CAN_RTR_FLAG) {
debug_print("remote request\n");
return ;
}
/* 打印数据长度 */
printf("[%d] ", frame->can_dlc);
/* 打印数据 */
for (int i = 0; i < frame->can_dlc; i++)
printf("%02x ", frame->data[i]);
printf("\n");
}
//static void pthread_write_quit_slot(int sig)
//{
// pthread_kill(thread_read_id,SIG_QUIT);
// pthread_join(thread_read_id);
// pthread_exit(0);
//}
#include "can_driver.h"
#define CAN_NUMBER "can0"
int main(void)
{
static unsigned int count=0,c2;
struct can_frame fram;
fram.can_dlc = 8;
can_rx_tx_init();
while(1){
if(can0_rx(&fram)>=0)
{
// print_can_frame(&fram);
fram.data[0] = count++;
fram.data[0] = c2--;
fram.can_id += count;
can0_tx(&fram);
}
}
}
收发现象:
3.设置CAN配置参数的命令和简单测试命令
ifconfig -a # 可以查到当前can网络 can0 can1,包括收发包数量、是否有错误等。
ip link set can0 up type can bitrate 800000 # 设置can0的波特率为800kbps,CAN网络波特率最大值为1Mbps
ip link set can0 up type can bitrate 800000 loopback on # 设置回环模式,自发自收,用于测试是硬件是否正常,loopback不一定支持
ip link set can0 down #关闭can0 网络 down换为 up则打开can0
cansend can0 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 # 发送默认ID为0x1的can标准帧,数据为0x11 22 33 44 55 66 77 88 每次最大8个byte
cansend can0 -i 0x800 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 -e # -e 表示扩展帧,CAN_ID最大29bit,标准帧CAN_ID最大11bit -i表示CAN_ID 0x800
cansend can0 -i 0x02 0x11 0x12 --loop=20 # --loop 表示发送20个包
candump can0 #接收CAN0数据