本帖最后由 dsl1784 于 2011-11-19 20:44 编辑
上位机控制下位机的一个协议。先上图。上位机发送数据包指令点亮二极管,下位机点亮LED,并在12864上显示当前状态。或者,上位机发送数据包指令点亮二极管,下位机点亮LED,并在12864上显示当前状态,在串口助手上面显示当前状态。
手机拍的效果不好。源码在最后面有完整的压缩包。大家一起学习了。
12864 用了PA 3 4 5。当然还有要与小3共地。
数据包格式 :
起始字 0x30
命令字 0xa0 参数跟 00 查询此时切换状态
0xa1 参数 00~07 切换通道命令
参数字
校验码 为命字与参数字的异或
结束字 0x31
例如:打开通道一 输入 0x30 0xa1 01 0xa0 0x31
查看当前状态 输入 0x30 0xa0 00 0xa0 0x31
下位机收到数据包后的回响包
起始字 0x30
命令接受字 00 正确接受并执行
01 下发命令字错误
02 下发参数错误
参数字 当前命令
校验码 为命字与参数字的异或
结束字 0x31
我找了好久,发现这个串口助手最好用。也一并传上来了。
UartAssist_47291.rar
(372.99 KB)
串口通信上下位置机协议.rar
(568.92 KB)
起始状态
上位机状态
选择通道后
LED
LCD
#include "systemInit.h"
#include "12864_SE.h"
#define OL3 GPIOPinWrite(GPIO_PORTD_BASE,GPIO_PIN_0,GPIO_PIN_0)
#define OL4 GPIOPinWrite(GPIO_PORTD_BASE,GPIO_PIN_1,GPIO_PIN_1)
#define OL5 GPIOPinWrite(GPIO_PORTB_BASE,GPIO_PIN_0,GPIO_PIN_0)
#define OL6 GPIOPinWrite(GPIO_PORTB_BASE,GPIO_PIN_1,GPIO_PIN_1)
#define OL7 GPIOPinWrite(GPIO_PORTE_BASE,GPIO_PIN_0,GPIO_PIN_0)
#define OL8 GPIOPinWrite(GPIO_PORTE_BASE,GPIO_PIN_1,GPIO_PIN_1)
#define CL3 GPIOPinWrite(GPIO_PORTD_BASE,GPIO_PIN_0,~GPIO_PIN_0)
#define CL4 GPIOPinWrite(GPIO_PORTD_BASE,GPIO_PIN_1,~GPIO_PIN_1)
#define CL5 GPIOPinWrite(GPIO_PORTB_BASE,GPIO_PIN_0,~GPIO_PIN_0)
#define CL6 GPIOPinWrite(GPIO_PORTB_BASE,GPIO_PIN_1,~GPIO_PIN_1)
#define CL7 GPIOPinWrite(GPIO_PORTE_BASE,GPIO_PIN_0,~GPIO_PIN_0)
#define CL8 GPIOPinWrite(GPIO_PORTE_BASE,GPIO_PIN_1,~GPIO_PIN_1)
void CL_ALL()
{
CL3;CL4;CL5;CL6;CL7;CL8;
}
void light_led(uchar x)
{
switch(x)
{
case 1:CL_ALL();OL3;break;
case 2:CL_ALL();OL4;break;
case 3:CL_ALL();OL5;break;
case 4:CL_ALL();OL6;break;
case 5:CL_ALL();OL7;break;
case 6:CL_ALL();OL8;break;
default :CL_ALL();
}
}
#define BEG 0x30 //起始字
#define END 0x31 //结束字
uchar channel = 0;
// 定义接收缓冲区
#define RX_BUF_SIZE 5 // 缓冲区最大限制长度
uchar RxBuf[RX_BUF_SIZE + 1]; // 接收缓冲区
uint RxIndex = 0; // 缓冲区位置变量
uchar RxEndFlag = false; // 接收结束标志
// 定义待发送的数据
#define TX_BUF_SIZE 5 // 缓冲区最大限制长度
uchar TxBuf[TX_BUF_SIZE + 1]; // 发送缓冲区
uint TxIndex = 0; // 发送冲区位置变量,对于发送数组大于16B的用得上
uchar TxEndFlag = false; // 发送结束的标志
// 通过UART 发送字符串 缓冲区小于16B用
void uart_puts(const char *s)
{
while (*s != '\0')
{
UARTCharPut(UART0_BASE,*(s++));
}
}
// 填充发送FIFO (填满FIFO 之后就退出,不会等待,缓冲区大于16用中断法)
void TX_Fill(void)
{
uchar c;
for (;;)
{
c = TxBuf[TxIndex];
if (c == '\0') // 若填充完毕
{
TxEndFlag = true; // 发送结束标志置位,并跳出
TxIndex = 0;
break;
}
if (UARTSpaceAvail(UART0_BASE)) // 若发送FIFO 里有可用空间
{
UARTCharPutNonBlocking(UART0_BASE,c);//填充发送FIFO
TxIndex++;
}
else // 若没有空间则跳出,不必等待
{
break;
}
}
}
void RX_Get(void)
{
uchar d;
while(UARTCharsAvail(UART0_BASE))//有字符接收
{
d = UARTCharGetNonBlocking(UART0_BASE);//从接收FIFO里读取字符
RxBuf[RxIndex] = d;
RxIndex++;
}
if(RxIndex>=5)
{
RxEndFlag = true;//一次接受完成
RxIndex = 0;
}
}
/*下位机 数据包处理函数*/
void pag_proc()
{
uchar resp=0; //回送响应包状态字
uchar jiaoyan = 0; //校验字
if((RxBuf[0]==BEG)&&(RxBuf[4]==END))//起始字 结束字检查
{
if((RxBuf[1]^RxBuf[2])==RxBuf[3])//校验字字检查
{
switch(RxBuf[1])
{
case 0xa0:
if(channel==0)
{
uart_puts("通道还未设置 ");
resp=0x03;
}
else
{
uart_puts("当前开启通道为: ");
UARTCharPut(UART0_BASE,channel+0x30);
write_com(0x01);//清显示
delay_nms(5);
write_str(2,1,"开启通道为: ");
lcd_pos(2,7);
write_data(channel+0x30);
}
break; //此指令为状态查询 只要将默认状态字写回 无操作
case 0xa1:
if((RxBuf[2]>0)&&(RxBuf[2]<=7))
{
channel = RxBuf[2];//参数传递 通道值
uart_puts("设置通道为: ");
UARTCharPut(UART0_BASE,channel+0x30);
light_led(channel);//对应操作
write_com(0x01);//清显示
delay_nms(5);
write_str(2,1,"当前通道为:");
lcd_pos(2,7);
write_data(channel+0x30);
}
else
{
resp = 0x01; //回递输入通道参数错误标示
uart_puts("通道设置错误");
write_com(0x01);//清显示
delay_nms(5);
write_str(2,1,"通道设置错误");
}
break;
default: resp = 0x02;
uart_puts("指令设置错误");
write_com(0x01);//清显示
delay_nms(5);
write_str(2,1,"指令设置错误");
break;//指令错误
}
jiaoyan = resp^channel;//以下的处理 上位机接收到做出相应操作
//回包数据压缩
TxBuf[0] = BEG+0x30;
TxBuf[1] = resp+0x30;
TxBuf[2] = channel+0x30;
TxBuf[3] = jiaoyan+0x30;
TxBuf[4] = END+0x30;
// TX_Fill();//回送数据包 因为工具关系改为输出字符跃
}
else
{
uart_puts("数据丢失");
write_com(0x01);//清显示
delay_nms(5);
write_str(2,1,"数据丢失");
}
}
else
{
uart_puts("数据格式错误");
write_com(0x01);//清显示
delay_nms(5);
write_str(2,1,"数据格式错误");
}
}
void disp_buf(uchar a)
{
write_data(a/100+0x30);
write_data(a/10%10+0x30);
write_data(a%10+0x30);
}
int main()
{
JtagWait();
clockInit();
GPIO_init();
func_init();
lcd_init();
uart_puts("串口正常开启");
while(1)
{
RX_Get();//接受数据到缓存
if(true == RxEndFlag)//有数据数据接受
{
pag_proc();//数据包处理
RxEndFlag = 0;
}
}
}
#include "12864_SE.h"
/*************************************
12864串行 Volatile
更改各个端口 注意下面初始化也要改
GPIOA 3 4 5口
**************************************/
void write_byte(unsigned char date)
{
unsigned char i=0;
for(i=0;i<8;i++)
{
if(date&0x80)
DI_1;
else
DI_0;
CLK_0;
delay_nus(1);
CLK_1;
delay_nus(12);
date<<=1;
}
}
void write_com(unsigned char cmd)
{
write_byte(0xf8);//写命令控制字
write_byte(cmd&0xf0);
cmd<<=4;
write_byte(cmd&0xf0);
}
void write_data(unsigned char data)
{
write_byte(0xfa);//写数据控制字
write_byte(data&0xf0);
data<<=4;
write_byte(data&0xf0);
}
/*设定显示位置*/
void lcd_pos(unsigned char X,unsigned char Y)
{
unsigned char pos;
if(X==1)
{X=0x80;}
else if(X==2)
{X=0x90;}
else if(X==3)
{X=0x88;}
else if(X==4)
{X=0x98;}
pos=X+Y-1;
write_com(pos);//显示地址
}
//=============给定字符串 写入到12864=============
void write_str(unsigned char hang,unsigned char lie,const unsigned char *p)
{
lcd_pos(hang,lie);
while(*p!='\0')
{
write_data(*p);
p++;
}
}
/*LCD初始化设定*/
void lcd_init()
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE,GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5);
CS_ON;//初始化 控制端
CLK_0;
write_com(0x30);//基本指令集 扩充指令集0x34
delay_nms(5);
write_com(0x0c);//显示开 光标关
delay_nms(5);
write_com(0x01);//清显示
delay_nms(5);
}
|