項目需求
(後補)
器件選型
(後補)
軟件設計
AtmelStudio環境下的ATSAMC21N開發配置
打開Atmel studio,用usb線把開發板連接至PC,Windows10自動安裝驅動,然後在Atmel studio上面會彈出板子的信息:
上面有關於此板子的信息,asf開發文檔,板子開發文檔等都在裏面。
新建項目,此配置參考Atmel的配置視頻。
輸入名字後進入選擇界面,選擇對應的MCU。
生成後的main.c文件如下所示:
/*
* RoadScannerDataAcquire.c
*
* Created: 2019-12-18 15:18:10
* Author : lenovo
*/
#include "sam.h"
int main(void)
{
/* Initialize the SAM system */
SystemInit();
/* Replace with your application code */
while (1)
{
}
}
爲了熟悉板子,本例用寄存器原始方式、ASF框架、Freertos三種開發形式上都進行實驗。保險起見,先把代碼上傳至Github。
創建Github
打開Github,
publish 到雲端賬號
寄存器方式(without ASF)
經查找SAM C21 Xplained Pro board的user guide,板子上有一個LED燈連接在PC的05腳上。本例用更改寄存器的方式實現對此燈的控制。
通過查看芯片的datasheet,找到以下兩個需要更改的寄存器。
端口設置爲輸出:
輸出設置爲低電平:
更改main函數:
int main(void)
{
/* Initialize the SAM system */
SystemInit();
/* Replace with your application code */
//將所有的PC口設置爲輸出。
REG_PORT_DIRSET2 = 0xffffffff;
//將所有的PC口置爲低電平以點亮LED。(LED另一端爲3.3V)
REG_PORT_OUTCLR2 = 0xffffffff;
while (1)
{
}
}
後來在官網找到了兄弟板的示例程序。並根據示例程序根據開發板做了更改,現在板子的LED在PC05腳,而示例程序的引腳在PA15腳。加載程序後LED以1hz的頻率閃爍。
#include "sam.h"
// I/O Ports definitions
#define PORTA (0ul)
#define PORTB (1ul)
#define PORTC (2ul)
// LED0 definitions
#define LED0_PORT PORTC
#define LED0_PIN_NUMBER (05ul)
#define LED0_PIN PORT_PC05
/** VARIABLES *****************************************************************/
static uint32_t ul_tickcount=0 ; // Global state variable for tick count
/** LOCAL PROTOTYPES **********************************************************/
void AppInit(void); // Application Hardware/Software Initialization
/** main() ********************************************************************/
int main(void){
/* Initialize the SAM system - auto-generated code */
SystemInit();
/* Application hardware and software initialization */
AppInit();
/* Replace with your application code */
while(1){
__NOP();
}
}
/*******************************************************************************
* Function: void AppInit(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This routine takes care of all of the hardware/software
* initialization that is required.
*
* Note:
*
******************************************************************************/
void AppInit(void){
/* Clock initialization (CPU, AHB, APBx)
The System RC Oscillator (RCSYS) provides the source for the main clock
at chip startup. It is set to 4 MHz.
Add code here to change the system clock
*/
// Assign the LED0 pin as OUTPUT
PORT->Group[LED0_PORT].DIRSET.reg = LED0_PIN ;
// Set the LED0 pin level, i.e. put to 3.3V -> this turns off the LED
PORT->Group[LED0_PORT].OUTSET.reg = LED0_PIN ;
// Configure SysTick to trigger every millisecond using the CPU Clock
SysTick->CTRL = 0; // Disable SysTick
SysTick->LOAD = 3999UL; // Set reload register for 1mS interrupts
NVIC_SetPriority(SysTick_IRQn, 3); // Set interrupt priority to least urgency
SysTick->VAL = 0; // Reset the SysTick counter value
SysTick->CTRL = 0x00000007; // Enable SysTick, Enable SysTick Exceptions, Use CPU Clock
NVIC_EnableIRQ(SysTick_IRQn); // Enable SysTick Interrupt
}
/*******************************************************************************
* Function: void SysTick_Handler(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This interrupt handler is called on SysTick timer underflow
*
* Note:
*
******************************************************************************/
void SysTick_Handler(void){
ul_tickcount++ ;
// Toggle LEDs every second (i.e. 1000ms)
if(ul_tickcount % 1000 == 0){
// Toggle LED pin output level.
PORT->Group[LED0_PORT].OUTTGL.reg = LED0_PIN ;
}
}
ASF
閱讀了官方的說明後,ASF4必須用Atmel START在線工具來配置。
添加完後改下名字,最後如下所示:
由於之前solution裏面已經有RoadScannerDataAcquire的project,所示創建失敗,由於之前Github已經配置好了,並不想重新配置,也不想改名,所以在Atmel studio 7裏面右擊project名字,點擊remove,刪除,記得要去在計算機端刪掉文件夾,否則之前的文件會干擾新文件的生成,造成未知的錯誤,然後再用原名稱導入就可以了。
創建完後打開,發現直接用板子上的USB下載口可以進行uart調試。查看手冊後發現引腳爲TX:PB10、 RX:PB11。
在Atmel Studio裏面選擇reconfigure,
打開後找到如下配置,更改引腳。發現驅動用的是同步的,也改爲異步。
更改時發現這兩個引腳PB11和PB10已經被SPI3給佔了,先去SPI配置裏面把這兩個口改爲其它引腳,把這兩個口空出來,然後再返回UART裏面設置這兩個口。
設置完成並重新生成後,找到生成的文件下的示例代碼並打開,
打開後找到如下代碼塊:
/**
* Example of using USART_3 to write "Hello World" using the IO abstraction.
*/
void USART_3_example(void)
{
struct io_descriptor *io;
usart_sync_get_io_descriptor(&USART_3, &io);
usart_sync_enable(&USART_3);
io_write(io, (uint8_t *)"Hello World!", 12);
}
因爲還會用到delay函數,同文件裏面找到delay的示例代碼:
void delay_example(void)
{
delay_ms(5000);
}
打開main.c,裏面生成的代碼如下:
#include <atmel_start.h>
int main(void)
{
/* Initializes MCU, drivers and middleware */
atmel_start_init();
/* Replace with your application code */
while (1) {
}
}
根據示例程序,將main.c改爲如下:
#include <atmel_start.h>
#include <driver_examples.h>
int main(void)
{
/* Initializes MCU, drivers and middleware */
atmel_start_init();
/* Replace with your application code */
while (1) {
USART_On_USBPort_example();
delay_ms(1000);
}
}
編譯並將代碼下載到板子。
前面改了uart的引腳好,爲的就是直接使用Atmel Studio裏面的Data Visualizer功能直接進行虛擬串口的調試。
打開data visualizer工具:
雙擊serial port:
設置:
點擊上面的connect,會彈出terminal終端,然後我們的板子會按照我們之前設計的每秒發送一次hello word。
ASF4的測試代碼到此結束。
FreeRTOS
再次打開配置:
點擊下能看到配置:
點擊freertos後,會出現其配置選項,在這裏用默認的即可。
點擊生成:
生成後找到如下rtos的示例代碼:
打開後代碼如下:
/*
* Code generated from Atmel Start.
*
* This file will be overwritten when reconfiguring your Atmel Start project.
* Please copy examples or other code you want to keep to a separate file or main.c
* to avoid loosing it when reconfiguring.
*/
#include "atmel_start.h"
#include "rtos_start.h"
#include "driver_examples.h"
#define TASK_EXAMPLE_STACK_SIZE (128 / sizeof(portSTACK_TYPE))
#define TASK_EXAMPLE_STACK_PRIORITY (tskIDLE_PRIORITY + 1)
static TaskHandle_t xCreatedExampleTask;
static SemaphoreHandle_t disp_mutex;
/**
* OS example task
*
* \param[in] p The void pointer for OS task Standard model.
*
*/
static void example_task(void *p)
{
(void)p;
while (1) {
if (xSemaphoreTake(disp_mutex, ~0)) {
/* add your code */
xSemaphoreGive(disp_mutex);
}
os_sleep(500);
}
}
/*
* Example
*/
void FREERTOS_V1000_0_example(void)
{
disp_mutex = xSemaphoreCreateMutex();
if (disp_mutex == NULL) {
while (1) {
;
}
}
if (xTaskCreate(
example_task, "Example", TASK_EXAMPLE_STACK_SIZE, NULL, TASK_EXAMPLE_STACK_PRIORITY, xCreatedExampleTask)
!= pdPASS) {
while (1) {
;
}
}
vTaskStartScheduler();
return;
}
上面的代碼簡單明瞭。在main裏面調用下,FreeRTOS就啓動了。在main函數裏面添加調用,添加了兩句,一句是爲了調用示例函數添加的#include “rtos_start.h”,另一句是調用函數FREERTOS_V1000_0_example(); 添加完這兩句後,原先main裏面的while死循環就永遠不會執行到了,任務由FreeRTOS調度。
如下所示:
#include <atmel_start.h>
#include <driver_examples.h>
#include "rtos_start.h"
int main(void)
{
/* Initializes MCU, drivers and middleware */
atmel_start_init();
FREERTOS_V1000_0_example();
/* Replace with your application code */
while (1) {
USART_On_USBPort_example();
delay_ms(1000);
}
}
返回rtos_start.c函數,添加#include "driver_examples.h"已引用我們前面的uart測試函數。然後在示例任務中加入串口調用函數,如下:
/**
* OS example task
*
* \param[in] p The void pointer for OS task Standard model.
*
*/
static void example_task(void *p)
{
(void)p;
while (1) {
if (xSemaphoreTake(disp_mutex, ~0)) {
/* add your code */
USART_On_USBPort_example();
// delay_ms(1000);
xSemaphoreGive(disp_mutex);
}
os_sleep(500);
}
}
運行後500ms輸出一次hello word。運行結果如下: