最近在做单片机的火焰传感器采集数据并且并且将危险信息发送给PC端的Linux。一直卡在Linux端的,所以,做了各种尝试,参考了网上一篇大神的代码,终于把自己的东西弄了出来。
先说明设备吧,CC2530单片机、linux下的pl2303的驱动、虚拟机环境下的CentOS以及minicom。
下面我把单片机端的代码贴出来:
/*
************************************************
*Name : serial_communication_CC2530 *
*Date : 2015-04-29 *
*Author : Sniper *
*Aim : fire sensor check the fire and send the *
* message to linux wihich though the *
* serial port. *
************************************************
*/
#include "ioCC2530.h"
#include <string.h>
#include <stdlib.h>
#define uchar unsigned char
#define uint unsigned int
void Uart_send_char(int data);
uchar Recdata[]="fire!";
/*
* init the clock
*/
void initclk(void)
{
SLEEPCMD&= ~0X04;
CLKCONCMD = 0X10;
while(CLKCONSTA!=0X10);
SLEEPCMD = 0X04; //主频32M
}
/*
*init the uart
*/
void inituart(void)
{
IEN0|=0x84;//总中断,接收中断使能
U0CSR|=0xc0;//UART模式,允许接收
U0GCR=10;
U0BAUD=59;
}
/*
*init the IO
*/
void initio(void)
{
P0SEL|=0x0c;
}
/*
*Uart send the string
*/
void UartTX_Send_String(uchar Data[],int len)
{
int j;
for(j=0;j<len;j++)
{
U0DBUF = *Data++;
while(UTX0IF == 0);
UTX0IF = 0;
}
}
/*
*fire sensor check the fire , if the fire is occured.
*It will send the message.
*/
int main(void)
{
initio();
initclk();
inituart();
P0DIR|=0x40;
int i=0;
while(1)
{
if((P0&0x20)&& (i==0))
{
UartTX_Send_String(Recdata,sizeof(Recdata));
i++;
}
else if(!(P0&0x20))
{
i=0;
}
}
}
/*
*interupt
*/
#pragma vector=URX0_VECTOR
__interrupt void UART0_IRQ(void)
{
URX0IF=0;
U0DBUF=U0DBUF;
while(!UTX0IF);
UTX0IF=0;
}
这个是linux端的代码,因为我用的设备设置是波特率38400、串口ttyUSB0、数据位8位、停止位1位、无校验方式。
/*
*************************************************
*Name : Serial_communication.c *
*Date : 2015-04-29 *
*Author : Sniper *
*Aim : make the CC2530 single chip and *
* Linux (CentOS) communication. *
* Linux receive and print the message*
*************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/*
*terminal device header file
*/
#include <termios.h>
#include <errno.h>
#include <string.h>
/*
*struct termios
*
struct termios{
unsigned short c_iflag; //输入模式标志
unsigned short c_oflag; //输出模式标志
unsigned short c_cflag; //控制模式标志
unsigned short c_lflag; //区域模式标志或本地模式标志或局部模式
unsigned char c_line; //行控制line discipline
unsigned char c_cc[NCC]; // 控制字符特性
};
*/
#define SERIAL_PORT "/dev/ttyUSB0" //串口地址
#define PORT_SPEED 38400 //串口波特率
#define DATABITS 8 //数据位
#define STOPBITS 1 //停止位
#define PARITY 'n' //校验方式 (不校验)
int setSpeed(int, int, struct termios*);
int setParity(int, int, int, int, struct termios);
int openPort(void);
int init(void);
void readPort(int);
int main()
{
char *quit = (char*)malloc(sizeof(char*));
int fd;
char write_buf[256];
memset(write_buf,'\0',sizeof(write_buf));
fd = init();//初始化端口设置
printf("configure complete\n");
printf("start send and receive data...\n");
while(1)
{
readPort(fd);
}
close(fd);
}
void readPort(int fd)
{
int i;
int len;
int n;
char read_buf[256];
memset(read_buf,'\0',sizeof(read_buf));
while(1)
{
bzero(read_buf, sizeof(read_buf));
while((n = read(fd, read_buf, sizeof(read_buf))) > 0)
{
printf("%s\n", read_buf);
}
}
}
/*
*init serial port
*1 failure, 0 success
*/
int init(void)
{
int fd;
struct termios opt; //定义termios结构
//打开串口
fd = openPort();
//设置波特率
if(setSpeed(fd, PORT_SPEED, &opt) == 1)
{
printf("setSpeed failed!\n");
exit(1);
}
//设置数据位、停止位和校验位
if(setParity(fd, DATABITS, STOPBITS, PARITY, opt) == 1)
{
printf("setParity failed!\n");
exit(1);
}
if(tcsetattr(fd, TCSANOW, &opt) != 0) //TCSANOW:不等数据传输完毕就立即改变属性。
{ //TCSADRAIN:等待所有数据传输结束才改变属性。
perror("serial error");
return -1;
}
return fd;
}
/*
*openPort function
*1 failure, 0 success
*/
int openPort()
{
int fd;
/*
*serial address is /dev/ttyUSB*, open the serial address
*/
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY |O_NDELAY);
if(fd == -1)
{
perror("open serial failed!\n");
exit(1);
}
return fd;
}
/*
*setSpeed
* SetSpeed(38400, 19200, 9600, 4800, 2400, 1200, 300)
* 1 failure, 0 success
*/
int setSpeed(int fd, int speed, struct termios *Opt)
{
int i;
if(tcgetattr(STDIN_FILENO, &Opt) != 0)
{
perror("tcgetattr fd\n");
return 1;
}
/*
*set speed
*/
tcflush(fd, TCIOFLUSH);
cfsetispeed(&Opt, speed);
cfsetospeed(&Opt, speed);
//set ways of receive
if(tcsetattr(fd, TCSANOW, &Opt) != 0)
{
perror("tcsetattr fd");
return 1;
}
tcflush(fd, TCIOFLUSH);
return 0;
}
/*
*setParity
*set the data bit,stop bit and check bit
* 1 failure, 0 success
*/
int setParity(int fd, int databits, int stopbits, int parity, struct termios Opt)
{
if(tcgetattr(fd, &Opt) != 0)
{
perror("tcgetattr fd");
return 1;
}
Opt.c_cflag |= (CLOCAL | CREAD);
/*
*Data bit
*/
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= CS8;
/*
*check bit
*/
Opt.c_cflag &= ~PARENB;
Opt.c_iflag &= ~INPCK;
/*
*stop bit
*/
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag |= (CLOCAL | CREAD);
Opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
Opt.c_oflag &= ~OPOST; //OPOST :启用具体实现自行定义的输出处理。
Opt.c_oflag &= ~(ONLCR | OCRNL); //OCRNL :将输出中的回车映射为新行符
//ONLCR :(XSI) 将输出中的新行符映射为回车-换行。
Opt.c_iflag &= ~(ICRNL | INLCR); //ICRNL :将输入中的回车翻译为新行 (除非设置了 IGNCR)(否则当输入信号有 CR 时不会终止输入)。
//INLCR :将输入中的 NL 翻译为 CR。(将收到的换行符号转换为Return)
Opt.c_iflag &= ~(IXON | IXOFF | IXANY); //IXON :启用输出的 XON/XOFF 流控制。
//IXOFF :启用输入的 XON/XOFF 流控制。
//IXANY :(不属于 POSIX.1;XSI) 允许任何字符来重新开始输出。
tcflush(fd, TCIFLUSH); //清空输入缓存
//MIN = 0 , TIME =0; 有READ立即回传否则传回 0,不读取任何字元
Opt.c_cc[VTIME] = 0;
Opt.c_cc[VMIN] = 0;
if(tcsetattr(fd, TCSANOW, &Opt) != 0) //设置数据接收方式
{
perror("tcsetattr fd");
return 1;
}
return 0;
}
运行方式:(1)生成可执行文件,执行。(2)打开minicom,设置相关参数。(3)接上单片机,并且打开电源。
linux端的代码参考了一下网址,此外,因为个人需要,做了相应的缩减,望大家批评指正:
http://blog.csdn.net/cooljun008/article/details/8181906
这个单片机可以使用别的单片机,只要通信的方式的参数对了,应该都可以通信。
下面一篇会分享两者通过串口双向通信,敬请期待!