论坛元老
 
- 积分
- 3347
- 金钱
- 3347
- 注册时间
- 2013-4-10
- 在线时间
- 333 小时
|
发表于 2016-3-1 22:00:26
|
显示全部楼层
本帖最后由 likunxue 于 2016-3-2 00:37 编辑
关建是你的串口协议要乍样来制定
1: 一次发送一个字节,或都一次发多个字节都没有问题
2:如果一次发送或接收的数据串大于5节个以上,我建义使用 STM32的DMA来做比较好
3:比如说, 你定议的协议为每个字节的 D7位是指令或数据标识, 1是指令,0是数据
哪么............. 这样吧, 我在做步进电机串行驱动是用过的一个485双向发送接收你可以参考一下,
不懂的地方可以问我!
如下是部份接收与发送的代码,你自已看看
/**************************************************************************************
模块名称: RS485驱动代码
文件名称: RS485.C
版 本: V1.0
**************************************************************************************/
#include "sys.h"
#include "rs485.h"
#include "delay.h"
#include "MOTOR.H" //步进电机配置头文件
#define TX_LED_ON() GPIOC->BRR = 1<<12 //开工作指示灯
#define TX_LED_OFF() GPIOC->BSRR = 1<<12 //关工作指示灯
#define SUA_SIZE 100u //串口接收,发送缓存区大小
vu16 SUA_FWDIR; //复位方向寄存器
vu16 R485_RX_BYTE;
vu16 RX_BYTE; //串口收到的16位参数
vu8 SUA_MCLK; //脉冲输出标志位
vu8 RX_DAT; //串口接收中的低7位数据寄存器
vu8 RX_QianZhiLing; //串口接收中的低位接收标志位
vu8 RX_STR; //串口接收缓存区指针
vu8 RX_Buf[SUA_SIZE]; //串口接收缓存数据区
vu8 TX_Buf[SUA_SIZE]; //串口2发送缓存区
/***************************************************************************************
函 数 名: DMA1的各通道配置
这里的传输形式是固定的,这点要根据不同的情况来修改
从存储器->外设模式/8位数据宽度/存储器增量模式
调 用: UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar)
参 数: DMA_CHx MA通道CHx
cpar:外设地址
cmar:存储器地址
返 回 值: 无
***************************************************************************************/
void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar)
{
RCC->AHBENR |= 1<<0; //开启DMA1时钟
delay_us(5);
DMA_CHx->CPAR = cpar; //DMA1 外设地址
DMA_CHx->CMAR = cmar; //DMA1,存储器地址
DMA_CHx->CCR = 0X00000000; //复位
DMA_CHx->CCR |= 1<<4; //从存储器读
DMA_CHx->CCR |= 0<<5; //普通模式
DMA_CHx->CCR |= 0<<6; //外设地址非增量模式
DMA_CHx->CCR |= 1<<7; //存储器增量模式
DMA_CHx->CCR |= 0<<8; //外设数据宽度为8位
DMA_CHx->CCR |= 0<<10; //存储器数据宽度8位
DMA_CHx->CCR |= 1<<12; //中等优先级
DMA_CHx->CCR |= 0<<14; //非存储器到存储器模式
}
/***************************************************************************************
函 数 名: 开启一次DMA传输
调 用: UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u8 len)
参 数: DMA_CHx MA通道CHx
len 需要传输的字节
返 回 值: 无
***************************************************************************************/
void UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u8 len)
{
DMA_CHx->CCR&=~(1<<0); //关闭DMA传输
DMA_CHx->CNDTR=len; //DMA1,传输数据量
DMA_CHx->CCR|=1<<0; //开启DMA传输
}
/*************************************************************************************
函 数 名:初始化IO 串口2
调 用:无
参 数:pclk1 CLK1时钟频率(Mhz)
bound:波特率
反 回 值: 无
**************************************************************************************/
void RS485_Init(u32 pclk1,u32 bound)
{
float temp;
u16 i, mantissa,fraction;
for(i =0; i< SUA_SIZE; i++){RX_Buf = 0; TX_Buf = 0;}//接收缓存区
RX_BYTE = 0; //串口收到的16位参数
RX_DAT = 0; //串口接收中的低7位数据寄存器
RX_QianZhiLing = 0; //串口接收中的低位接收标志位
RX_STR = 0; //串口接收缓存区指针
temp=(float)(pclk1*1000000)/(bound*16);//得到USARTDIV
mantissa=temp; //得到整数部分
fraction=(temp-mantissa)*16; //得到小数部分
mantissa<<=4;
mantissa+=fraction;
RCC->APB2ENR |= 1<<2; //使能PORTA口时钟
GPIOA->CRL &= 0XFFFF00FF; //IO状态设置
GPIOA->CRL |= 0X00008B00; //IO状态设置
RCC->APB1ENR |= 1<<17; //使能串口时钟
RCC->APB1RSTR |= 1<<17; //复位串口2
RCC->APB1RSTR &= ~(1<<17); //停止复位
RCC->APB2ENR |= 1<<4; //使能C时钟
GPIOC->CRH &= 0xfff0ffff;
GPIOC->CRH |= 0x00030000; //PC12设为输出
GPIOC->ODR |= 1<<12; //初始化为高电平,关闭状态
//波特率设置
USART2->BRR = mantissa; //波特率设置
USART2->CR1 |= 1<<13; //串口2使能(UE,USATR)
USART2->CR1 |= 1<<2; //接收使能(RE)
USART2->CR1 |= 1<<3; //发送使能(TE)
USART2->CR1 |= 1<<8; //PE中断使能
USART2->CR1 |= 1<<5; //接收缓冲区非空中断使能
USART2->CR3 = 1<<7; //使能串口2的DMA发送
//DMA1通道7,外设为串口2,存储器为TX_BUF
UART_DMA_Config(DMA1_Channel7,(u32)&USART2->DR,(u32)TX_Buf); //初始化DMA
MY_NVIC_Init(0,0,USART2_IRQn,4); //抢占5,子优先级0,组4
MOTOR_TIM7_Init(); //初始化定时器7
R485_RX_BYTE = 0;
PEND_OUT = 0; //关电机失步报警灯
}
/*************************************************************************************
函 数 名: 向主机传送双字节参数(串口中断函数调用)
调 用: TX_FASONG_Byte(u16 Dat)
参 数: Dat 需要发送的参数
反 回 值: 无
**************************************************************************************/
void TX_FASONG_Byte(u16 Dat)
{
u8 S0 = Dat;
u8 S1 = Dat >> 8;
TX_LED_ON(); //开工作指示灯
while(DMA1_Channel7->CNDTR != 0); //等待通道7传输完成
TX_Buf[0] = S0 & 0x7f; //发送低7位
TX_Buf[1] = ((S0 >> 7) & 0x07)|0x88; //初始化指令码
TX_Buf[2] = S1 & 0x7f; //发送低7位
TX_Buf[3] = ((S1 >> 7) & 0x07)|0x98; //结束码,并使能读取
UART_DMA_Enable(DMA1_Channel7,4); //通过DMA发送出去4个字节
}
/*************************************************************************************
函 数 名: 多字节参数解码(串口中断函数调用)
调 用: SUA_CANSHUJIEMA(void)
参 数: 无
反 回 值: 无
说 明: 接收6个字节,前面4个是双字节参数,第5个为功能码,第6个是指令码0x90
高字节在后,低字节在前.
**************************************************************************************/
void SUA_CANSHUJIEMA(void)
{
if((RX_STR ==2)&&(RX_QianZhiLing == 0xE5))
{
u16 Bul =(u16)(RX_Buf[1]<<8)+ RX_Buf[0]; //取得数据
TX_LED_ON(); //开工作指示灯
switch(RX_DAT)
{
case 12: MoB.XIFEN[Motor_Z] = Bul;break; //0号机细分参数X
case 13: MoB.XIFEN[Motor_R] = Bul;break; //1号机细分参数Z
case 14: MoB.XIFEN[Motor_T] = Bul;break; //2号机细分参数R
case 15: MoB.XIFEN[Motor_O] = Bul;break; //3号机细分参数T
case 22: MoB.DIANLIU[Motor_Z]= Bul;break; //0号机电流参数X
case 23: MoB.DIANLIU[Motor_R]= Bul;break; //1号机电流参数Z
case 24: MoB.DIANLIU[Motor_T]= Bul;break; //2号机电流参数R
case 25: MoB.DIANLIU[Motor_O]= Bul;break; //3号机电流参数T
case 50: MoB.FINE = Bul;break; //伺服细分参数
case 51: MoB.QDSD = Bul;break; //伺服起动速度
case 52: MoB.ZGSD = Bul;break; //伺服最高工作速度
case 53: MoB.JiaSuShiJian = Bul;break;//伺服加速时间
case 54: MoB.BianSuBi = Bul;break; //伺服变速比
case 55: MoB.SDTJ = Bul;break; //伺服速度调节变量
case 70:{//重配电机参数
if(Bul == 0x55aa)MOTOR_CanShuZhongPei();//参数配置
}break;
case 99:R485_RX_BYTE = Bul; break; //用于显示主机发来的测试数据
}
}
}
/*************************************************************************************
函 数 名: RS485中断接收函数(双字节指令模式)
调 用: 无
参 数: 无
反 回 值: 无
自定义数据接收格式
**************************************************************************************/
void USART2_IRQHandler(void)
{
if(USART2->SR&(1<<5)) //接收到数据
{
u8 K = USART2->DR; //读取串口数据
USART2->SR &= ~(1<<5); //清中断接收标志位
if(K < 0x80){RX_DAT = K;RX_QianZhiLing = 0xE5;}//数据低7位
else{
u8 Bul = K & 0xf8; //得到指令码
switch(Bul)
{
case 0x80:{//是数据字节(双字节指令码)
if(RX_QianZhiLing == 0XE5)
{
TX_LED_ON(); //开通信指示灯
if(RX_STR >SUA_SIZE)RX_STR = 0;
RX_Buf[RX_STR ++] = (K <<7)|RX_DAT; //保存数据
}
}break;
case 0x88:{//多字节参数初始化
if(RX_QianZhiLing == 0XE5)
{
TX_LED_ON(); //开通信指示灯
RX_STR = 0;
RX_Buf[RX_STR ++] = (K <<7)|RX_DAT;
}
}break;
case 0x90:{//收到电机方向数据(双字节指令码)
if(RX_QianZhiLing == 0XE5)
{
u8 Bii = (RX_DAT >> 4)&0x01;//得到方向标志
u8 rr1 = RX_DAT & 0x0f; //得到电机编号
TX_LED_ON(); //开工作指示灯
switch(rr1) //高位机地址
{//机头板
}
}
}break;
case 0x98:{//工作电机脉冲(双字节指令码)
if(RX_QianZhiLing == 0xe5)
{
u16 S0 = (((u16)(K & 0x07))<< 7 )|RX_DAT; //得到10位数据位
u8 Bul = (u8)((S0>>2)&0x0f); //得到脉冲数据
if(Bul != 0)
{
}
}
}break;
case 0xB0:break;
case 0xB8:break;//位置坐标同步
default:{ //以下指令为快速指令码,全部为单字节
switch(K)
{
case 0xE0:SUA_CANSHUJIEMA();break;//多字节参数解码(0xB0)
case 0xE1:{//关闭电机
TX_LED_ON(); //开通信指示灯
if(TASK_MOBF() == ERR_OK)MOTOR_ENBL_OFF(); //电机在位置纠正时禁止关电机
}break;
}
}break;
}
RX_QianZhiLing = 0x80; //清标志位
}
}
}
|
|