1.原因
課題需要通過stm32 usart3驅動485協議。
2.硬件
RE和DE都下拉,PA08是sp3485的發送/接收使能端,sp3485只能支持半雙工的通信,這個引腳就是來控制這個芯片到底是收數據還是發數據。這個電路有以下幾個問題:
(1)A B 沒做上下拉,那麼如果A B線空閒的情況下,線上電壓在SP3485門限電壓-200mv~200mv之間,邏輯電平不確定,可能導致總線上出現莫名的數據。 (2)A B線之間沒有TVS,防止總線浪湧,在浪湧出現的情況下,可能導致芯片損壞。 (3)另外,如果環境複雜,還要考慮二次的防雷擊浪湧保護以及電源隔離,放置地平面環流。
3.sp3485
來源:周立功sp345
4.程序
初始化程序
void ConfigurationUsart3(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* config USART3,PA.8 clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
/* USART3 GPIO config */
/* Configure USART3 Tx (PB.10) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure USART3 Rx (PB.11) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* USART3 mode config */
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
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(USART3, &USART_InitStructure);
USART_Cmd(USART3, ENABLE);
/*USART3 Direction Config PA.8*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIOA->ODR &= ~GPIO_Pin_8; //拉低電平接受使能
}
主程序
int main(void)
{
int i=3;
SystemInit();
ConfigurationUsart3();
while(i--)
{
GPIOA->ODR |= GPIO_Pin_8; //拉高電平 發送使能
USART3_printf( USART3, "This is a usart3_printf demo \r\n " );
Command_Delay(200); //等待發送完成
GPIOA->ODR &= ~GPIO_Pin_8; // 拉低電平,等待接受
}
}
發送打印程序
/*
* 函數名:itoa 指針函數
* 描述 :將整形數據轉換成字符串
* 輸入 :-radix =10 表示10進制,其他結果爲0
* -value 要轉換的整形數
* -buf 轉換後的字符串
* -radix = 10
* 輸出 :無
* 返回 :無
* 調用 :被USART3_printf()調用
*/
static char *itoa(int value, char *string, int radix)
{
int i, d;
int flag = 0;
char *ptr = string;
/* This implementation only works for decimal numbers. */
if (radix != 10)
{
*ptr = 0;
return string;
}
if (!value)
{
*ptr++ = 0x30;
*ptr = 0;
return string;
}
/* if this is a negative value insert the minus sign. */
if (value < 0)
{
*ptr++ = '-';
/* Make the value positive. */
value *= -1;
}
for (i = 10000; i > 0; i /= 10)
{
d = value / i;
if (d || flag)
{
*ptr++ = (char)(d + 0x30);
value -= (d * i);
flag = 1;
}
}
/* Null terminate the string. */
*ptr = 0;
return string;
} /* NCL_Itoa */
/*
* 函數名:USART_printf
* 描述 :格式化輸出,類似於C庫中的printf,但這裏沒有用到C庫
* 輸入 :-USARTx 串口通道,這裏只用到了串口2,即USART2
* -Data 要發送到串口的內容的指針
* -... 其他參數
* 輸出 :無
* 返回 :無
* 調用 :外部調用
* 典型應用USART3_printf( USART2, "\r\n this is a demo \r\n" );
* USART3_printf( USART2, "\r\n %d \r\n", i );
* USART3_printf( USART2, "\r\n %s \r\n", j );
*/
void USART3_printf(USART_TypeDef* USARTx, uint8_t *Data,...)
{
const char *s;
int d;
char buf[16];
va_list ap;
va_start(ap, Data);
while ( *Data != 0) // 判斷是否到達字符串結束符
{
if ( *Data == 0x5c ) //'\'
{
switch ( *++Data )
{
case 'r': //回車符
USART_SendData(USARTx, 0x0d);
Data ++;
break;
case 'n': //換行符
USART_SendData(USARTx, 0x0a);
Data ++;
break;
default:
Data ++;
break;
}
}
else if ( *Data == '%')
{ //
switch ( *++Data )
{
case 's': //字符串
s = va_arg(ap, const char *);
for ( ; *s; s++)
{
USART_SendData(USARTx,*s);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}
Data++;
break;
case 'd': //十進制
d = va_arg(ap, int);
itoa(d, buf, 10);
for (s = buf; *s; s++)
{
USART_SendData(USARTx,*s);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}
Data++;
break;
default:
Data++;
break;
}
} /* end of else if */
else USART_SendData(USARTx, *Data++);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );
}
}
5、完整程序代碼