实验内容
用32最小系统板模拟一个AX12舵机,用32精英板作为控制器。简单模拟控制器与AX12的通信过程。
最小系统板部分:
①通过单线(实验过程中选择PA2)与精英板通信,接收指令包。
②收到指令包后,发送反馈的状态包给精英板。
精英板内容:
①用串口1(PA9,PA10)与电脑通信。
②用单线(实验过程中选择PA2)与最小系统板通信。
具体实现:
按下精英版的KEY0,发送改变舵机ID的指令包给最小板,最小板收到指令包后,如果校验码没有错误,灯亮五秒后发送数据(符合要求格式)给精英板。精英板接收到数据后,把校验码发给电脑串口。(因为重点研究通信问题,故舵机多种功能不加以模拟)
相关理论内容
1.指令包与状态包的格式
需要关注INSTRUCTION内容:
需要关注的PARAMETER参数:
重点代码
精英板部分:
1.半双工引脚的配置
关于简单实现半双工通信可以参考我的另一篇博客
https://blog.csdn.net/npuqiyi/article/details/105301081#comments
void uart2_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能USART2,GPIOA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //使能USART2,GPIOA时钟
//USART2_TX GPIOA.2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2
//Usart2 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART2, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART2, ENABLE); //使能串口1
USART2->CR2&=~(1<<11);
USART2->CR2&=~(1<<14);
USART2->CR3|=1<<3;
USART2->CR3&=~(1<<1);
USART2->CR3&=~(1<<5);
}
2.向舵机发送指令包
因为半双工模式下,PA2和PA3是连接在一起的,所以串口发送数据也会触发中断,于是我软件设置了模式选择,平时处于接收模式,只有需要时才出于发送模式。在中断服务函数中,只有接收模式的数据是有效的。
void Rudder_ID_Change(u8 IDO,u8 IDN)
{
COMMAND[0]=0XFF;
COMMAND[1]=0XFF;
COMMAND[2]=IDO;
COMMAND[3]=0X04;
COMMAND[4]=0X03;
COMMAND[5]=0X03;
COMMAND[6]=IDN;
COMMAND[7]=~(COMMAND[2]+COMMAND[3]+COMMAND[4]+COMMAND[5]+COMMAND[6]);
LEN=8; //生成指令
MODE=MODE_TXD;
Usart2_Send_Data(COMMAND,LEN); //发送指令
printf("ID-CHANGE");
MODE=MODE_RXD;
USART2_RX_STA=0; //接收模式配置
memset(USART2_RX_BUF,0,sizeof(USART2_RX_BUF));
}
3.串口服务函数
void USART2_IRQHandler(void) //串口2中断服务程序
{
u8 Res;
static unsigned char sum=0;
u8 i;
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntEnter();
#endif
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART2); //读取接收到的数据
if(MODE==MODE_RXD)//必须为接收模式数据才有效
{
USART2_RX_BUF[USART2_RX_STA&0X3FFF]=Res ;
USART2_RX_STA++;
if(USART2_RX_BUF[0]!=0xff) USART2_RX_STA--;
if((USART2_RX_STA&0X3FFF)>3)//收到长度
{
if((USART2_RX_BUF[0]==0xff)&&(USART2_RX_BUF[1]==0xff))//检验包头
{
if((USART2_RX_STA&0X3FFF)==USART2_RX_BUF[3]+4)//接收完成
{
for(i=2;i<(USART2_RX_STA&0X3FFF)-1;i++)
{
sum+=USART2_RX_BUF[i];
}
sum=~sum;
printf(" sum: %d ",sum);
if(sum==USART2_RX_BUF[(USART2_RX_STA&0X3FFF)-1])//满足校验
{
USART2_RX_STA|=0x8000;//接收终止位置1
}
}
}
}
}
}
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntExit();
#endif
}
Res =USART_ReceiveData(USART2);这一句一定要保留,不然会出现程序卡死。
**if(USART2_RX_BUF[0]!=0xff) USART2_RX_STA–;**这一句也很重要,因为串口发送数据时,往往会先发送一个无效数据,这样可以通过包头的判断清除无效数据。
4.主函数
int main(void)
{
u8 key;
u16 times=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
uart2_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
KEY_Init(); //初始化与按键连接的硬件接口
BEEP_Init();
USART_SendData(USART2, 0);
while(USART_GetFlagStatus(USART2,USART_FLAG_TC)!=SET);//防止有效数据丢失
printf("CHUANKOU");
while(1)
{
key=KEY_Scan(0);//先用电脑发给单片机,再按KEY0发回来
if(key==KEY0_PRES) //接收模式
{
printf("KEY0-PRES");
Rudder_ID_Change(1,0);
}
else if(key==KEY1_PRES)
{
printf("%s",USART2_RX_BUF);
}
else
{
times++;
if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
delay_ms(10);
}
}
}
最小系统板部分
最小系统板部分我直接以精英部分代码为模板,内容基本一样。
int main(void)
{
u8 key;
u16 times=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
uart2_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
USART_SendData(USART2, 0);//第一次发的第一个数据(空闲帧)会丢失,这样就可以了
while(USART_GetFlagStatus(USART2,USART_FLAG_TC)!=SET);
printf("CHUANKOU");
MODE=MODE_RXD;
while(1)
{
if(USART2_RX_STA&0x8000)
{
LED0=0;
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
Rudder_ID_Change(1,0);
}
else
{
times++;
if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
delay_ms(10);
}
}
}
相关代码资源,不需要积分,感兴趣的人可以看一看。
https://download.csdn.net/download/npuqiyi/12302305