在這一節(jié)里我們來一起完成STM32F407VE中的串行總線功能。所謂串行總線就是我們常常說的串口。串口中的信號線(數(shù)據(jù)線)只有2條,一條線為Tx,另一條為Rx,也就是發(fā)送線和接收線。所以稱它為串行,就是通過一根信號線的產(chǎn)生一個(gè)序列的高低電平來完成數(shù)字信號中一個(gè)字節(jié)的數(shù)據(jù)。例如:我們知道計(jì)算機(jī)中都是采用二進(jìn)制來表示數(shù)的,如果我們需要在串行總線上傳輸一個(gè)字節(jié)的數(shù)據(jù),如0x5A,那么這個(gè)字節(jié)的二進(jìn)制為:01011010,所以我們就需要讓串行總線產(chǎn)生的高低電平序列為:低、高、低、高、高、低、高、低,每一個(gè)高低電平,我們在計(jì)算機(jī)中稱之為Bit(比特):
這樣,我們就知道串行總線所產(chǎn)生的高低電平時(shí)序了。其實(shí)除了正常數(shù)據(jù)傳輸所用到的Bit位之外,串行總線還有數(shù)據(jù)傳輸?shù)目刂茦?biāo)記位,通常有起始位、停止位和校驗(yàn)位,但在我們實(shí)際使用串行總線時(shí)常常只使用一個(gè)起始位和一個(gè)停止位而不使用校驗(yàn)位。于是,我們使用STM32的標(biāo)準(zhǔn)庫來完成串行總線的配置工作。首先來配置串口的NVIC中斷:
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
我們使用的是USART2,也就是串口2。我們將其主優(yōu)先級設(shè)置為2,子優(yōu)先級設(shè)置為0。接下來配置串口2的兩個(gè)信號線引腳PA2和PA3:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
最后,配置串口的相關(guān)參數(shù)和中斷方式:
USART_InitTypeDef USART_InitStructure;
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;
USART2- >CR1 |= (USART_CR1_RE | USART_CR1_TE);
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_Cmd(USART2, ENABLE);
在這里,我們將串口2的波特率設(shè)置為115200,并設(shè)置數(shù)據(jù)位為8Bit,一個(gè)停止位,無校驗(yàn)位。并設(shè)置了接收和發(fā)送中斷。
這樣,我們就完成了串口2的配置工作,接下來我們需要完成兩個(gè)函數(shù),分別用于串口數(shù)據(jù)的發(fā)送和接收:
void uart_write(uint8_t data)
{
int next_head = tx_head + 1;
if (next_head >= tx_buff_size)
{
next_head = 0;
}
while (next_head == tx_foot)
{
}
tx_buff[tx_head] = data;
tx_head = next_head;
USART2- >CR1 |= USART_FLAG_TXE;
}
int uart_read(uint8_t* ch)
{
int foot = rx_foot;
if (rx_head == foot)
{
return 0;
}
else
{
uint8_t data = rx_buff[foot];
foot++;
if (foot >= rx_buff_size)
{
foot = 0;
}
rx_foot = foot;
*ch = data;
return 1;
}
}
void uart_data_in(uint8_t data)
{
int next_head = rx_head + 1;
if (next_head >= rx_buff_size)
{
next_head = 0;
}
if (next_head != rx_foot)
{
rx_buff[rx_head] = data;
rx_head = next_head;
}
else
{
next_head++;
next_head--;
}
}
void USART2_IRQHandler(void)
{
//UART1
int foot = 0;
uint8_t data = 0;
if (USART2- >SR & USART_FLAG_RXNE)
{
data = USART2- >DR & 0x1FF;
uart_data_in(data);
}
if (USART2- >SR & USART_FLAG_TXE)
{
foot = tx_foot;
if (foot != tx_head)
{
USART2- >DR = tx_buff[foot];
foot++;
if (foot >= tx_buff_size)
{
foot = 0;
}
tx_foot = foot;
}
else
{
USART2- >CR1 &= ~USART_FLAG_TXE;
USART2- >SR = ~USART_FLAG_TXE;
}
}
}
實(shí)際上,串口的發(fā)送和接收都是采用了void USART2_IRQHandler()串口2的中斷函數(shù)來完成的,當(dāng)我們需要發(fā)送一個(gè)字節(jié)的數(shù)據(jù)時(shí),調(diào)用void uart_write(uint8_t data)函數(shù)將data這個(gè)字節(jié)的數(shù)據(jù)存放到發(fā)送隊(duì)列(發(fā)送緩沖區(qū))當(dāng)中,并同時(shí)打開發(fā)送中斷。在發(fā)送中斷函數(shù)中從發(fā)送隊(duì)列當(dāng)中取出需要發(fā)送的字節(jié)發(fā)送到串行總線上。
相反的,當(dāng)接收總線上收到一個(gè)字節(jié)的數(shù)據(jù)時(shí),就會產(chǎn)生一個(gè)接收中斷,void USART2_IRQHandler()接收中斷函數(shù)調(diào)用void uart_data_in(uint8_t data)函數(shù)將這個(gè)字節(jié)的數(shù)據(jù)存放到接收隊(duì)列(接收緩沖區(qū))當(dāng)中,而我們通過調(diào)用int uart_read(uint8_t* ch)函數(shù)來從接收隊(duì)列中讀取接收到的數(shù)據(jù)。
于是,我們可以在main()函數(shù)中對串口2進(jìn)行初始化配置,并使用它來與上位機(jī)軟件進(jìn)行通信:
int main(int argc, char* argv[])
{
init_led();
uart_init();
char buff[100] = {0};
while (1)
{
uart_write(0x5A);
GPIO_WriteBit(GPIOE, GPIO_Pin_0, 1);
GPIO_WriteBit(GPIOE, GPIO_Pin_1, 0);
for (int i = 0; i < 500000; i++)
{
}
GPIO_WriteBit(GPIOE, GPIO_Pin_0, 0);
GPIO_WriteBit(GPIOE, GPIO_Pin_1, 1);
for (int i = 0; i < 500000; i++)
{
}
}
}
我們使用上機(jī)的串口讀寫程序來得到STM32通過串口發(fā)送的數(shù)據(jù):
我們可以使用邏輯分析儀來查看串行總線上每一個(gè)字節(jié)的傳輸方式:
我們可以看到串行總線上的Bit位序列為0 01011010 1 ,其中第一個(gè)0為起始位,最后一個(gè)1為停止位,而中間的01011010為8個(gè)Bit的數(shù)據(jù)位,轉(zhuǎn)成16進(jìn)制則是0x5A。這樣我們就完成了STM32F407VE的串行總線配置和數(shù)據(jù)發(fā)送,而數(shù)據(jù)接收與發(fā)送的原理是一樣的,我們不再贅述。
-
STM32
+關(guān)注
關(guān)注
2270文章
10906瀏覽量
356484 -
中斷
+關(guān)注
關(guān)注
5文章
899瀏覽量
41540 -
串口
+關(guān)注
關(guān)注
14文章
1555瀏覽量
76632 -
串行總線
+關(guān)注
關(guān)注
1文章
183瀏覽量
30651
發(fā)布評論請先 登錄
相關(guān)推薦
評論